* [PATCH 3/6] VSOCK: notification implementation.
From: George Zhang @ 2013-01-08 23:59 UTC (permalink / raw)
To: netdev, linux-kernel, georgezhang, virtualization
Cc: pv-drivers, gregkh, davem
In-Reply-To: <20130108235633.3719.6085.stgit@promb-2n-dhcp175.eng.vmware.com>
VSOCK control notifications for VMCI Stream Sockets protocol.
Signed-off-by: George Zhang <georgezhang@vmware.com>
Acked-by: Andy king <acking@vmware.com>
Acked-by: Dmitry Torokhov <dtor@vmware.com>
---
net/vmw_vsock/notify.c | 675 ++++++++++++++++++++++++++++++++++++++++++++++++
net/vmw_vsock/notify.h | 124 +++++++++
2 files changed, 799 insertions(+), 0 deletions(-)
create mode 100644 net/vmw_vsock/notify.c
create mode 100644 net/vmw_vsock/notify.h
diff --git a/net/vmw_vsock/notify.c b/net/vmw_vsock/notify.c
new file mode 100644
index 0000000..23bad8b
--- /dev/null
+++ b/net/vmw_vsock/notify.c
@@ -0,0 +1,675 @@
+/*
+ * VMware vSockets Driver
+ *
+ * Copyright (C) 2009-2012 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/stddef.h>
+#include <net/sock.h>
+
+#include "notify.h"
+#include "af_vsock.h"
+
+#define PKT_FIELD(vsk, field_name) ((vsk)->notify.pkt.field_name)
+
+#define VSOCK_MAX_DGRAM_RESENDS 10
+
+static bool vsock_vmci_notify_waiting_write(struct vsock_vmci_sock *vsk)
+{
+#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
+ bool retval;
+ u64 notify_limit;
+
+ if (!PKT_FIELD(vsk, peer_waiting_write))
+ return false;
+
+#ifdef VSOCK_OPTIMIZATION_FLOW_CONTROL
+ /* When the sender blocks, we take that as a sign that the sender is
+ * faster than the receiver. To reduce the transmit rate of the sender,
+ * we delay the sending of the read notification by decreasing the
+ * write_notify_window. The notification is delayed until the number of
+ * bytes used in the queue drops below the write_notify_window.
+ */
+
+ if (!PKT_FIELD(vsk, peer_waiting_write_detected)) {
+ PKT_FIELD(vsk, peer_waiting_write_detected) = true;
+ if (PKT_FIELD(vsk, write_notify_window) < PAGE_SIZE) {
+ PKT_FIELD(vsk, write_notify_window) =
+ PKT_FIELD(vsk, write_notify_min_window);
+ } else {
+ PKT_FIELD(vsk, write_notify_window) -= PAGE_SIZE;
+ if (PKT_FIELD(vsk, write_notify_window) <
+ PKT_FIELD(vsk, write_notify_min_window))
+ PKT_FIELD(vsk, write_notify_window) =
+ PKT_FIELD(vsk, write_notify_min_window);
+
+ }
+ }
+ notify_limit = vsk->consume_size - PKT_FIELD(vsk, write_notify_window);
+#else
+ notify_limit = 0;
+#endif
+
+ /* For now we ignore the wait information and just see if the free
+ * space exceeds the notify limit. Note that improving this function
+ * to be more intelligent will not require a protocol change and will
+ * retain compatibility between endpoints with mixed versions of this
+ * function.
+ *
+ * The notify_limit is used to delay notifications in the case where
+ * flow control is enabled. Below the test is expressed in terms of
+ * free space in the queue: if free_space > ConsumeSize -
+ * write_notify_window then notify An alternate way of expressing this
+ * is to rewrite the expression to use the data ready in the receive
+ * queue: if write_notify_window > bufferReady then notify as
+ * free_space == ConsumeSize - bufferReady.
+ */
+ retval = vmci_qpair_consume_free_space(vsk->qpair) > notify_limit;
+#ifdef VSOCK_OPTIMIZATION_FLOW_CONTROL
+ if (retval) {
+ /*
+ * Once we notify the peer, we reset the detected flag so the
+ * next wait will again cause a decrease in the window size.
+ */
+
+ PKT_FIELD(vsk, peer_waiting_write_detected) = false;
+ }
+#endif
+ return retval;
+#else
+ return true;
+#endif
+}
+
+static bool vsock_vmci_notify_waiting_read(struct vsock_vmci_sock *vsk)
+{
+#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
+ if (!PKT_FIELD(vsk, peer_waiting_read))
+ return false;
+
+ /* For now we ignore the wait information and just see if there is any
+ * data for our peer to read. Note that improving this function to be
+ * more intelligent will not require a protocol change and will retain
+ * compatibility between endpoints with mixed versions of this
+ * function.
+ */
+ return vmci_qpair_produce_buf_ready(vsk->qpair) > 0;
+#else
+ return true;
+#endif
+}
+
+static void
+vsock_vmci_handle_waiting_read(struct sock *sk,
+ struct vsock_packet *pkt,
+ bool bottom_half,
+ struct sockaddr_vm *dst,
+ struct sockaddr_vm *src)
+{
+#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
+ struct vsock_vmci_sock *vsk;
+
+ vsk = vsock_sk(sk);
+
+ PKT_FIELD(vsk, peer_waiting_read) = true;
+ memcpy(&PKT_FIELD(vsk, peer_waiting_read_info), &pkt->u.wait,
+ sizeof(PKT_FIELD(vsk, peer_waiting_read_info)));
+
+ if (vsock_vmci_notify_waiting_read(vsk)) {
+ bool sent;
+
+ if (bottom_half)
+ sent = VSOCK_SEND_WROTE_BH(dst, src) > 0;
+ else
+ sent = VSOCK_SEND_WROTE(sk) > 0;
+
+ if (sent)
+ PKT_FIELD(vsk, peer_waiting_read) = false;
+
+ }
+#endif
+}
+
+static void
+vsock_vmci_handle_waiting_write(struct sock *sk,
+ struct vsock_packet *pkt,
+ bool bottom_half,
+ struct sockaddr_vm *dst,
+ struct sockaddr_vm *src)
+{
+#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
+ struct vsock_vmci_sock *vsk;
+
+ vsk = vsock_sk(sk);
+
+ PKT_FIELD(vsk, peer_waiting_write) = true;
+ memcpy(&PKT_FIELD(vsk, peer_waiting_write_info), &pkt->u.wait,
+ sizeof(PKT_FIELD(vsk, peer_waiting_write_info)));
+
+ if (vsock_vmci_notify_waiting_write(vsk)) {
+ bool sent;
+
+ if (bottom_half)
+ sent = VSOCK_SEND_READ_BH(dst, src) > 0;
+ else
+ sent = VSOCK_SEND_READ(sk) > 0;
+
+ if (sent)
+ PKT_FIELD(vsk, peer_waiting_write) = false;
+
+ }
+#endif
+}
+
+static void
+vsock_vmci_handle_read(struct sock *sk,
+ struct vsock_packet *pkt,
+ bool bottom_half,
+ struct sockaddr_vm *dst, struct sockaddr_vm *src)
+{
+#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
+ struct vsock_vmci_sock *vsk;
+
+ vsk = vsock_sk(sk);
+ PKT_FIELD(vsk, sent_waiting_write) = false;
+#endif
+
+ sk->sk_write_space(sk);
+}
+
+static bool vsock_vmci_send_waiting_read(struct sock *sk, u64 room_needed)
+{
+#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
+ struct vsock_vmci_sock *vsk;
+ struct vsock_waiting_info waiting_info;
+ u64 tail;
+ u64 head;
+ u64 room_left;
+ bool ret;
+
+ vsk = vsock_sk(sk);
+
+ if (PKT_FIELD(vsk, sent_waiting_read))
+ return true;
+
+ if (PKT_FIELD(vsk, write_notify_window) < vsk->consume_size)
+ PKT_FIELD(vsk, write_notify_window) =
+ min(PKT_FIELD(vsk, write_notify_window) + PAGE_SIZE,
+ vsk->consume_size);
+
+ vmci_qpair_get_consume_indexes(vsk->qpair, &tail, &head);
+ room_left = vsk->consume_size - head;
+ if (room_needed >= room_left) {
+ waiting_info.offset = room_needed - room_left;
+ waiting_info.generation =
+ PKT_FIELD(vsk, consume_q_generation) + 1;
+ } else {
+ waiting_info.offset = head + room_needed;
+ waiting_info.generation = PKT_FIELD(vsk, consume_q_generation);
+ }
+
+ ret = VSOCK_SEND_WAITING_READ(sk, &waiting_info) > 0;
+ if (ret)
+ PKT_FIELD(vsk, sent_waiting_read) = true;
+
+ return ret;
+#else
+ return true;
+#endif
+}
+
+static bool vsock_vmci_send_waiting_write(struct sock *sk, u64 room_needed)
+{
+#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
+ struct vsock_vmci_sock *vsk;
+ struct vsock_waiting_info waiting_info;
+ u64 tail;
+ u64 head;
+ u64 room_left;
+ bool ret;
+
+ vsk = vsock_sk(sk);
+
+ if (PKT_FIELD(vsk, sent_waiting_write))
+ return true;
+
+ vmci_qpair_get_produce_indexes(vsk->qpair, &tail, &head);
+ room_left = vsk->produce_size - tail;
+ if (room_needed + 1 >= room_left) {
+ /* Wraps around to current generation. */
+ waiting_info.offset = room_needed + 1 - room_left;
+ waiting_info.generation = PKT_FIELD(vsk, produce_q_generation);
+ } else {
+ waiting_info.offset = tail + room_needed + 1;
+ waiting_info.generation =
+ PKT_FIELD(vsk, produce_q_generation) - 1;
+ }
+
+ ret = VSOCK_SEND_WAITING_WRITE(sk, &waiting_info) > 0;
+ if (ret)
+ PKT_FIELD(vsk, sent_waiting_write) = true;
+
+ return ret;
+#else
+ return true;
+#endif
+}
+
+static int vsock_vmci_send_read_notification(struct sock *sk)
+{
+ struct vsock_vmci_sock *vsk;
+ bool sent_read;
+ unsigned int retries;
+ int err;
+
+ vsk = vsock_sk(sk);
+ sent_read = false;
+ retries = 0;
+ err = 0;
+
+ if (vsock_vmci_notify_waiting_write(vsk)) {
+ /* Notify the peer that we have read, retrying the send on
+ * failure up to our maximum value. XXX For now we just log
+ * the failure, but later we should schedule a work item to
+ * handle the resend until it succeeds. That would require
+ * keeping track of work items in the vsk and cleaning them up
+ * upon socket close.
+ */
+ while (!(vsk->peer_shutdown & RCV_SHUTDOWN) &&
+ !sent_read && retries < VSOCK_MAX_DGRAM_RESENDS) {
+ err = VSOCK_SEND_READ(sk);
+ if (err >= 0)
+ sent_read = true;
+
+ retries++;
+ }
+
+ if (retries >= VSOCK_MAX_DGRAM_RESENDS)
+ pr_err("%p unable to send read notify to peer\n", sk);
+ else
+#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
+ PKT_FIELD(vsk, peer_waiting_write) = false;
+#endif
+
+ }
+ return err;
+}
+
+static void
+vsock_vmci_handle_wrote(struct sock *sk,
+ struct vsock_packet *pkt,
+ bool bottom_half,
+ struct sockaddr_vm *dst, struct sockaddr_vm *src)
+{
+#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
+ struct vsock_vmci_sock *vsk;
+
+ vsk = vsock_sk(sk);
+ PKT_FIELD(vsk, sent_waiting_read) = false;
+#endif
+
+ sk->sk_data_ready(sk, 0);
+}
+
+static void vsock_vmci_notify_pkt_socket_init(struct sock *sk)
+{
+ struct vsock_vmci_sock *vsk;
+ vsk = vsock_sk(sk);
+
+ PKT_FIELD(vsk, write_notify_window) = PAGE_SIZE;
+ PKT_FIELD(vsk, write_notify_min_window) = PAGE_SIZE;
+ PKT_FIELD(vsk, peer_waiting_read) = false;
+ PKT_FIELD(vsk, peer_waiting_write) = false;
+ PKT_FIELD(vsk, peer_waiting_write_detected) = false;
+ PKT_FIELD(vsk, sent_waiting_read) = false;
+ PKT_FIELD(vsk, sent_waiting_write) = false;
+ PKT_FIELD(vsk, produce_q_generation) = 0;
+ PKT_FIELD(vsk, consume_q_generation) = 0;
+
+ memset(&PKT_FIELD(vsk, peer_waiting_read_info), 0,
+ sizeof(PKT_FIELD(vsk, peer_waiting_read_info)));
+ memset(&PKT_FIELD(vsk, peer_waiting_write_info), 0,
+ sizeof(PKT_FIELD(vsk, peer_waiting_write_info)));
+}
+
+static void vsock_vmci_notify_pkt_socket_destruct(struct sock *sk)
+{
+ return;
+}
+
+static int
+vsock_vmci_notify_pkt_poll_in(struct sock *sk,
+ size_t target, bool *data_ready_now)
+{
+ struct vsock_vmci_sock *vsk = vsock_sk(sk);
+
+ if (vsock_vmci_stream_has_data(vsk)) {
+ *data_ready_now = true;
+ } else {
+ /* We can't read right now because there is nothing in the
+ * queue. Ask for notifications when there is something to
+ * read.
+ */
+ if (sk->sk_state == SS_CONNECTED) {
+ if (!vsock_vmci_send_waiting_read(sk, 1))
+ return -1;
+
+ }
+ *data_ready_now = false;
+ }
+
+ return 0;
+}
+
+static int
+vsock_vmci_notify_pkt_poll_out(struct sock *sk,
+ size_t target, bool *space_avail_now)
+{
+ s64 produce_q_free_space;
+ struct vsock_vmci_sock *vsk = vsock_sk(sk);
+
+ produce_q_free_space = vsock_vmci_stream_has_space(vsk);
+ if (produce_q_free_space > 0) {
+ *space_avail_now = true;
+ return 0;
+ } else if (produce_q_free_space == 0) {
+ /* This is a connected socket but we can't currently send data.
+ * Notify the peer that we are waiting if the queue is full. We
+ * only send a waiting write if the queue is full because
+ * otherwise we end up in an infinite WAITING_WRITE, READ,
+ * WAITING_WRITE, READ, etc. loop. Treat failing to send the
+ * notification as a socket error, passing that back through
+ * the mask.
+ */
+ if (!vsock_vmci_send_waiting_write(sk, 1))
+ return -1;
+
+ *space_avail_now = false;
+ }
+
+ return 0;
+}
+
+static int
+vsock_vmci_notify_pkt_recv_init(struct sock *sk,
+ size_t target,
+ struct vsock_vmci_recv_notify_data *data)
+{
+ struct vsock_vmci_sock *vsk;
+
+ vsk = vsock_sk(sk);
+
+#ifdef VSOCK_OPTIMIZATION_WAITING_NOTIFY
+ data->consume_head = 0;
+ data->produce_tail = 0;
+#ifdef VSOCK_OPTIMIZATION_FLOW_CONTROL
+ data->notify_on_block = false;
+
+ if (PKT_FIELD(vsk, write_notify_min_window) < target + 1) {
+ PKT_FIELD(vsk, write_notify_min_window) = target + 1;
+ if (PKT_FIELD(vsk, write_notify_window) <
+ PKT_FIELD(vsk, write_notify_min_window)) {
+ /* If the current window is smaller than the new
+ * minimal window size, we need to reevaluate whether
+ * we need to notify the sender. If the number of ready
+ * bytes are smaller than the new window, we need to
+ * send a notification to the sender before we block.
+ */
+
+ PKT_FIELD(vsk, write_notify_window) =
+ PKT_FIELD(vsk, write_notify_min_window);
+ data->notify_on_block = true;
+ }
+ }
+#endif
+#endif
+
+ return 0;
+}
+
+static int
+vsock_vmci_notify_pkt_recv_pre_block(struct sock *sk,
+ size_t target,
+ struct vsock_vmci_recv_notify_data *data)
+{
+ int err = 0;
+
+ /* Notify our peer that we are waiting for data to read. */
+ if (!vsock_vmci_send_waiting_read(sk, target)) {
+ err = -EHOSTUNREACH;
+ return err;
+ }
+#ifdef VSOCK_OPTIMIZATION_FLOW_CONTROL
+ if (data->notify_on_block) {
+ err = vsock_vmci_send_read_notification(sk);
+ if (err < 0)
+ return err;
+
+ data->notify_on_block = false;
+ }
+#endif
+
+ return err;
+}
+
+static int
+vsock_vmci_notify_pkt_recv_pre_dequeue(struct sock *sk,
+ size_t target,
+ struct vsock_vmci_recv_notify_data *data)
+{
+ struct vsock_vmci_sock *vsk = vsock_sk(sk);
+
+ /* Now consume up to len bytes from the queue. Note that since we have
+ * the socket locked we should copy at least ready bytes.
+ */
+#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
+ vmci_qpair_get_consume_indexes(vsk->qpair,
+ &data->produce_tail,
+ &data->consume_head);
+#endif
+
+ return 0;
+}
+
+static int
+vsock_vmci_notify_pkt_recv_post_dequeue(struct sock *sk,
+ size_t target,
+ ssize_t copied,
+ bool data_read,
+ struct vsock_vmci_recv_notify_data *data)
+{
+ struct vsock_vmci_sock *vsk;
+ int err;
+
+ vsk = vsock_sk(sk);
+ err = 0;
+
+ if (data_read) {
+#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
+ /* Detect a wrap-around to maintain queue generation. Note
+ * that this is safe since we hold the socket lock across the
+ * two queue pair operations.
+ */
+ if (copied >= vsk->consume_size - data->consume_head)
+ PKT_FIELD(vsk, consume_q_generation)++;
+
+#endif
+
+ err = vsock_vmci_send_read_notification(sk);
+ if (err < 0)
+ return err;
+
+ }
+ return err;
+}
+
+static int
+vsock_vmci_notify_pkt_send_init(struct sock *sk,
+ struct vsock_vmci_send_notify_data *data)
+{
+#ifdef VSOCK_OPTIMIZATION_WAITING_NOTIFY
+ data->consume_head = 0;
+ data->produce_tail = 0;
+#endif
+
+ return 0;
+}
+
+static int
+vsock_vmci_notify_pkt_send_pre_block(struct sock *sk,
+ struct vsock_vmci_send_notify_data *data)
+{
+ /* Notify our peer that we are waiting for room to write. */
+ if (!vsock_vmci_send_waiting_write(sk, 1))
+ return -EHOSTUNREACH;
+
+ return 0;
+}
+
+static int
+vsock_vmci_notify_pkt_send_pre_enqueue(struct sock *sk,
+ struct vsock_vmci_send_notify_data *data)
+{
+ struct vsock_vmci_sock *vsk = vsock_sk(sk);
+
+#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
+ vmci_qpair_get_produce_indexes(vsk->qpair,
+ &data->produce_tail,
+ &data->consume_head);
+#endif
+
+ return 0;
+}
+
+static int
+vsock_vmci_notify_pkt_send_post_enqueue(struct sock *sk,
+ ssize_t written,
+ struct vsock_vmci_send_notify_data *data)
+{
+ int err = 0;
+ struct vsock_vmci_sock *vsk;
+ bool sent_wrote = false;
+ int retries = 0;
+
+ vsk = vsock_sk(sk);
+
+#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
+ /* Detect a wrap-around to maintain queue generation. Note that this
+ * is safe since we hold the socket lock across the two queue pair
+ * operations.
+ */
+ if (written >= vsk->produce_size - data->produce_tail)
+ PKT_FIELD(vsk, produce_q_generation)++;
+
+#endif
+
+ if (vsock_vmci_notify_waiting_read(vsk)) {
+ /* Notify the peer that we have written, retrying the send on
+ * failure up to our maximum value. See the XXX comment for the
+ * corresponding piece of code in StreamRecvmsg() for potential
+ * improvements.
+ */
+ while (!(vsk->peer_shutdown & RCV_SHUTDOWN) &&
+ !sent_wrote && retries < VSOCK_MAX_DGRAM_RESENDS) {
+ err = VSOCK_SEND_WROTE(sk);
+ if (err >= 0)
+ sent_wrote = true;
+
+ retries++;
+ }
+
+ if (retries >= VSOCK_MAX_DGRAM_RESENDS) {
+ pr_err("%p unable to send wrote notify to peer\n", sk);
+ return err;
+ } else {
+#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
+ PKT_FIELD(vsk, peer_waiting_read) = false;
+#endif
+ }
+ }
+ return err;
+}
+
+static void
+vsock_vmci_notify_pkt_handle_pkt(struct sock *sk,
+ struct vsock_packet *pkt,
+ bool bottom_half,
+ struct sockaddr_vm *dst,
+ struct sockaddr_vm *src, bool *pkt_processed)
+{
+ bool processed = false;
+
+ switch (pkt->type) {
+ case VSOCK_PACKET_TYPE_WROTE:
+ vsock_vmci_handle_wrote(sk, pkt, bottom_half, dst, src);
+ processed = true;
+ break;
+ case VSOCK_PACKET_TYPE_READ:
+ vsock_vmci_handle_read(sk, pkt, bottom_half, dst, src);
+ processed = true;
+ break;
+ case VSOCK_PACKET_TYPE_WAITING_WRITE:
+ vsock_vmci_handle_waiting_write(sk, pkt, bottom_half, dst, src);
+ processed = true;
+ break;
+
+ case VSOCK_PACKET_TYPE_WAITING_READ:
+ vsock_vmci_handle_waiting_read(sk, pkt, bottom_half, dst, src);
+ processed = true;
+ break;
+ }
+
+ if (pkt_processed)
+ *pkt_processed = processed;
+
+}
+
+static void vsock_vmci_notify_pkt_process_request(struct sock *sk)
+{
+ struct vsock_vmci_sock *vsk = vsock_sk(sk);
+
+ PKT_FIELD(vsk, write_notify_window) = vsk->consume_size;
+ if (vsk->consume_size < PKT_FIELD(vsk, write_notify_min_window))
+ PKT_FIELD(vsk, write_notify_min_window) = vsk->consume_size;
+
+}
+
+static void vsock_vmci_notify_pkt_process_negotiate(struct sock *sk)
+{
+ struct vsock_vmci_sock *vsk = vsock_sk(sk);
+
+ PKT_FIELD(vsk, write_notify_window) = vsk->consume_size;
+ if (vsk->consume_size < PKT_FIELD(vsk, write_notify_min_window))
+ PKT_FIELD(vsk, write_notify_min_window) = vsk->consume_size;
+
+}
+
+/* Socket control packet based operations. */
+struct vsock_vmci_notify_ops vsock_vmci_notify_pkt_ops = {
+ vsock_vmci_notify_pkt_socket_init,
+ vsock_vmci_notify_pkt_socket_destruct,
+ vsock_vmci_notify_pkt_poll_in,
+ vsock_vmci_notify_pkt_poll_out,
+ vsock_vmci_notify_pkt_handle_pkt,
+ vsock_vmci_notify_pkt_recv_init,
+ vsock_vmci_notify_pkt_recv_pre_block,
+ vsock_vmci_notify_pkt_recv_pre_dequeue,
+ vsock_vmci_notify_pkt_recv_post_dequeue,
+ vsock_vmci_notify_pkt_send_init,
+ vsock_vmci_notify_pkt_send_pre_block,
+ vsock_vmci_notify_pkt_send_pre_enqueue,
+ vsock_vmci_notify_pkt_send_post_enqueue,
+ vsock_vmci_notify_pkt_process_request,
+ vsock_vmci_notify_pkt_process_negotiate,
+};
diff --git a/net/vmw_vsock/notify.h b/net/vmw_vsock/notify.h
new file mode 100644
index 0000000..dc52217
--- /dev/null
+++ b/net/vmw_vsock/notify.h
@@ -0,0 +1,124 @@
+/*
+ * VMware vSockets Driver
+ *
+ * Copyright (C) 2009-2012 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef __NOTIFY_H__
+#define __NOTIFY_H__
+
+#include <linux/types.h>
+
+#include "vsock_common.h"
+#include "vsock_packet.h"
+
+/* Comment this out to compare with old protocol. */
+#define VSOCK_OPTIMIZATION_WAITING_NOTIFY 1
+#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY)
+/* Comment this out to remove flow control for "new" protocol */
+#define VSOCK_OPTIMIZATION_FLOW_CONTROL 1
+#endif
+
+#define VSOCK_MAX_DGRAM_RESENDS 10
+
+#define NOTIFYCALLRET(vsk, rv, mod_fn, args...) \
+ do { \
+ if (vsk->notify_ops && \
+ vsk->notify_ops->mod_fn != NULL) \
+ rv = (vsk->notify_ops->mod_fn)(args); \
+ else \
+ rv = 0; \
+ \
+ } while (0)
+
+#define NOTIFYCALL(vsk, mod_fn, args...) \
+ do { \
+ if (vsk->notify_ops && \
+ vsk->notify_ops->mod_fn != NULL) \
+ (vsk->notify_ops->mod_fn)(args); \
+ \
+ } while (0)
+
+struct vsock_vmci_notify_pkt {
+ u64 write_notify_window;
+ u64 write_notify_min_window;
+ bool peer_waiting_read;
+ bool peer_waiting_write;
+ bool peer_waiting_write_detected;
+ bool sent_waiting_read;
+ bool sent_waiting_write;
+ struct vsock_waiting_info peer_waiting_read_info;
+ struct vsock_waiting_info peer_waiting_write_info;
+ u64 produce_q_generation;
+ u64 consume_q_generation;
+};
+
+struct vsock_vmci_notify_pkt_q_state {
+ u64 write_notify_window;
+ u64 write_notify_min_window;
+ bool peer_waiting_write;
+ bool peer_waiting_write_detected;
+};
+
+union vsock_vmci_notify {
+ struct vsock_vmci_notify_pkt pkt;
+ struct vsock_vmci_notify_pkt_q_state pkt_q_state;
+};
+
+struct vsock_vmci_recv_notify_data {
+ u64 consume_head;
+ u64 produce_tail;
+ bool notify_on_block;
+};
+
+struct vsock_vmci_send_notify_data {
+ u64 consume_head;
+ u64 produce_tail;
+};
+
+/* Socket notification callbacks. */
+struct vsock_vmci_notify_ops {
+ void (*socket_init) (struct sock *sk);
+ void (*socket_destruct) (struct sock *sk);
+ int (*poll_in) (struct sock *sk, size_t target,
+ bool *data_ready_now);
+ int (*poll_out) (struct sock *sk, size_t target,
+ bool *space_avail_now);
+ void (*handle_notify_pkt) (struct sock *sk, struct vsock_packet *pkt,
+ bool bottom_half, struct sockaddr_vm *dst,
+ struct sockaddr_vm *src,
+ bool *pkt_processed);
+ int (*recv_init) (struct sock *sk, size_t target,
+ struct vsock_vmci_recv_notify_data *data);
+ int (*recv_pre_block) (struct sock *sk, size_t target,
+ struct vsock_vmci_recv_notify_data *data);
+ int (*recv_pre_dequeue) (struct sock *sk, size_t target,
+ struct vsock_vmci_recv_notify_data *data);
+ int (*recv_post_dequeue) (struct sock *sk, size_t target,
+ ssize_t copied, bool data_read,
+ struct vsock_vmci_recv_notify_data *data);
+ int (*send_init) (struct sock *sk,
+ struct vsock_vmci_send_notify_data *data);
+ int (*send_pre_block) (struct sock *sk,
+ struct vsock_vmci_send_notify_data *data);
+ int (*send_pre_enqueue) (struct sock *sk,
+ struct vsock_vmci_send_notify_data *data);
+ int (*send_post_enqueue) (struct sock *sk, ssize_t written,
+ struct vsock_vmci_send_notify_data *data);
+ void (*process_request) (struct sock *sk);
+ void (*process_negotiate) (struct sock *sk);
+};
+
+extern struct vsock_vmci_notify_ops vsock_vmci_notify_pkt_ops;
+extern struct vsock_vmci_notify_ops vsock_vmci_notify_pkt_q_state_ops;
+
+#endif /* __NOTIFY_H__ */
^ permalink raw reply related
* [PATCH 4/6] VSOCK: statistics implementation.
From: George Zhang @ 2013-01-09 0:00 UTC (permalink / raw)
To: netdev, linux-kernel, georgezhang, virtualization
Cc: pv-drivers, gregkh, davem
In-Reply-To: <20130108235633.3719.6085.stgit@promb-2n-dhcp175.eng.vmware.com>
VSOCK stats for VMCI Stream Sockets protocol.
Signed-off-by: George Zhang <georgezhang@vmware.com>
Acked-by: Andy king <acking@vmware.com>
Acked-by: Dmitry Torokhov <dtor@vmware.com>
---
net/vmw_vsock/stats.c | 30 ++++++++++
net/vmw_vsock/stats.h | 150 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 180 insertions(+), 0 deletions(-)
create mode 100644 net/vmw_vsock/stats.c
create mode 100644 net/vmw_vsock/stats.h
diff --git a/net/vmw_vsock/stats.c b/net/vmw_vsock/stats.c
new file mode 100644
index 0000000..49e09bb
--- /dev/null
+++ b/net/vmw_vsock/stats.c
@@ -0,0 +1,30 @@
+/*
+ * VMware vSockets Driver
+ *
+ * Copyright (C) 2009-2012 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/stddef.h>
+#include <net/sock.h>
+
+#include "af_vsock.h"
+#include "stats.h"
+
+#ifdef VSOCK_GATHER_STATISTICS
+u64 vsock_stats_ctl_pkt_count[VSOCK_PACKET_TYPE_MAX];
+u64 vsock_stats_consume_queue_hist[VSOCK_NUM_QUEUE_LEVEL_BUCKETS];
+u64 vsock_stats_produce_queue_hist[VSOCK_NUM_QUEUE_LEVEL_BUCKETS];
+atomic64_t vsock_stats_consume_total;
+atomic64_t vsock_stats_produce_total;
+#endif
diff --git a/net/vmw_vsock/stats.h b/net/vmw_vsock/stats.h
new file mode 100644
index 0000000..07e2bf0
--- /dev/null
+++ b/net/vmw_vsock/stats.h
@@ -0,0 +1,150 @@
+/*
+ * VMware vSockets Driver
+ *
+ * Copyright (C) 2009-2012 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef __STATS_H__
+#define __STATS_H__
+
+#include <linux/types.h>
+
+#include "vsock_common.h"
+#include "vsock_packet.h"
+
+/* Define VSOCK_GATHER_STATISTICS to turn on statistics gathering. Currently
+ * this consists of 3 types of stats: 1. The number of control datagram
+ * messages sent. 2. The level of queuepair fullness (in 10% buckets) whenever
+ * data is about to be enqueued or dequeued from the queuepair. 3. The total
+ * number of bytes enqueued/dequeued.
+ */
+
+#ifdef VSOCK_GATHER_STATISTICS
+
+#define VSOCK_NUM_QUEUE_LEVEL_BUCKETS 10
+extern u64 vsock_stats_ctl_pkt_count[VSOCK_PACKET_TYPE_MAX];
+extern u64 vsock_stats_consume_queue_hist[VSOCK_NUM_QUEUE_LEVEL_BUCKETS];
+extern u64 vsock_stats_produce_queue_hist[VSOCK_NUM_QUEUE_LEVEL_BUCKETS];
+extern atomic64_t vsock_stats_consume_total;
+extern atomic64_t vsock_stats_produce_total;
+
+#define VSOCK_STATS_STREAM_CONSUME_HIST(vsk) \
+ vsock_vmci_stats_update_queue_bucket_count((vsk)->qpair, \
+ (vsk)->consume_size, \
+ vmci_qpair_consume_buf_ready((vsk)->qpair), \
+ vsock_stats_consume_queue_hist)
+#define VSOCK_STATS_STREAM_PRODUCE_HIST(vsk) \
+ vsock_vmci_stats_update_queue_bucket_count((vsk)->qpair, \
+ (vsk)->produce_size, \
+ vmci_qpair_produce_buf_ready((vsk)->qpair), \
+ vsock_stats_produce_queue_hist)
+#define VSOCK_STATS_CTLPKT_LOG(pkt_type) \
+ (++vsock_stats_ctl_pkt_count[pkt_type])
+#define VSOCK_STATS_STREAM_CONSUME(bytes) \
+ atomic64_add(&vsock_stats_consume_total, bytes)
+#define VSOCK_STATS_STREAM_PRODUCE(bytes) \
+ atomic64_add(&vsock_stats_produce_total, bytes)
+#define VSOCK_STATS_CTLPKT_DUMP_ALL() vsock_vmci_stats_ctl_pkt_dump_all()
+#define VSOCK_STATS_HIST_DUMP_ALL() vsock_vmci_stats_hist_dump_all()
+#define VSOCK_STATS_TOTALS_DUMP_ALL() vsock_vmci_stats_totals_dump_all()
+#define VSOCK_STATS_RESET() vsock_vmci_stats_reset()
+
+static inline void
+vsock_vmci_stats_update_queue_bucket_count(vmci_qpair *qpair,
+ u64 queue_size,
+ u64 data_ready,
+ u64 queue_hist[])
+{
+ u64 bucket = 0;
+ u32 remainder = 0;
+
+ /* We can't do 64 / 64 = 64 bit divides on linux because it requires a
+ * libgcc which is not linked into the kernel module. Since this code
+ * is only used by developers we just limit the queue_size to be less
+ * than MAX_UINT for now.
+ */
+ Div643264(data_ready * 10, queue_size, &bucket, &remainder);
+ ++queue_hist[bucket];
+}
+
+static inline void vsock_vmci_stats_ctl_pkt_dump_all(void)
+{
+ int index;
+
+ BUILD_BUG_ON(VSOCK_PACKET_TYPE_MAX !=
+ ARRAY_SIZE(vsock_stats_ctl_pkt_count));
+
+ for (index = 0; index < ARRAY_SIZE(vsock_stats_ctl_pkt_count);
+ index++) {
+ pr_info("Control packet: Type = %u, Count = %" FMT64
+ "u\n", index, vsock_stats_ctl_pkt_count[index]);
+ }
+}
+
+static inline void vsock_vmci_stats_hist_dump_all(void)
+{
+ int index;
+
+#define VSOCK_DUMP_HIST(strname, name) do { \
+ for (index = 0; index < ARRAY_SIZE(name); index++) { \
+ printk(strname " Bucket count %u = %"FMT64"u\n", \
+ index, name[index]); \
+ } \
+ } while (0)
+
+ VSOCK_DUMP_HIST("Produce Queue", vsock_stats_produce_queue_hist);
+ VSOCK_DUMP_HIST("Consume Queue", vsock_stats_consume_queue_hist);
+
+#undef VSOCK_DUMP_HIST
+}
+
+static inline void vsock_vmci_stats_totals_dump_all(void)
+{
+ pr_info("Produced %" FMT64 "u total bytes\n",
+ atomic64_read(&vsock_stats_produce_total));
+ pr_info("Consumed %" FMT64 "u total bytes\n",
+ atomic64_read(&vsock_stats_consume_total));
+}
+
+static inline void vsock_vmci_stats_reset(void)
+{
+ int index;
+
+#define VSOCK_RESET_ARRAY(name) do { \
+ for (index = 0; index < ARRAY_SIZE(name); index++) { \
+ name[index] = 0; \
+ } \
+ } while (0)
+
+ VSOCK_RESET_ARRAY(vsock_stats_ctl_pkt_count);
+ VSOCK_RESET_ARRAY(vsock_stats_produce_queue_hist);
+ VSOCK_RESET_ARRAY(vsock_stats_consume_queue_hist);
+
+#undef VSOCK_RESET_ARRAY
+
+ atomic64_set(&vsock_stats_consume_total, 0);
+ atomic64_set(&vsock_stats_produce_total, 0);
+}
+
+#else
+#define VSOCK_STATS_STREAM_CONSUME_HIST(vsk)
+#define VSOCK_STATS_STREAM_PRODUCE_HIST(vsk)
+#define VSOCK_STATS_STREAM_PRODUCE(bytes)
+#define VSOCK_STATS_STREAM_CONSUME(bytes)
+#define VSOCK_STATS_CTLPKT_LOG(pkt_type)
+#define VSOCK_STATS_CTLPKT_DUMP_ALL()
+#define VSOCK_STATS_HIST_DUMP_ALL()
+#define VSOCK_STATS_TOTALS_DUMP_ALL()
+#define VSOCK_STATS_RESET()
+#endif
+
+#endif
^ permalink raw reply related
* [PATCH 5/6] VSOCK: utility functions.
From: George Zhang @ 2013-01-09 0:00 UTC (permalink / raw)
To: netdev, linux-kernel, georgezhang, virtualization
Cc: pv-drivers, gregkh, davem
In-Reply-To: <20130108235633.3719.6085.stgit@promb-2n-dhcp175.eng.vmware.com>
VSOCK utility functions for Linux VSocket module.
Signed-off-by: George Zhang <georgezhang@vmware.com>
Acked-by: Andy king <acking@vmware.com>
Acked-by: Dmitry Torokhov <dtor@vmware.com>
---
net/vmw_vsock/util.c | 345 ++++++++++++++++++++++++++++++++++++++++++++++++++
net/vmw_vsock/util.h | 187 +++++++++++++++++++++++++++
2 files changed, 532 insertions(+), 0 deletions(-)
create mode 100644 net/vmw_vsock/util.c
create mode 100644 net/vmw_vsock/util.h
diff --git a/net/vmw_vsock/util.c b/net/vmw_vsock/util.c
new file mode 100644
index 0000000..b77cafa
--- /dev/null
+++ b/net/vmw_vsock/util.c
@@ -0,0 +1,345 @@
+/*
+ * VMware vSockets Driver
+ *
+ * Copyright (C) 2007-2012 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/socket.h>
+#include <linux/stddef.h>
+#include <net/sock.h>
+
+#include "af_vsock.h"
+#include "util.h"
+
+struct list_head vsock_bind_table[VSOCK_HASH_SIZE + 1];
+struct list_head vsock_connected_table[VSOCK_HASH_SIZE];
+
+DEFINE_SPINLOCK(vsock_table_lock);
+
+void vsock_vmci_log_pkt(char const *function, u32 line,
+ struct vsock_packet *pkt)
+{
+ char buf[256];
+ char *cur = buf;
+ int left = sizeof(buf);
+ int written = 0;
+ char *type_strings[] = {
+ [VSOCK_PACKET_TYPE_INVALID] = "INVALID",
+ [VSOCK_PACKET_TYPE_REQUEST] = "REQUEST",
+ [VSOCK_PACKET_TYPE_NEGOTIATE] = "NEGOTIATE",
+ [VSOCK_PACKET_TYPE_OFFER] = "OFFER",
+ [VSOCK_PACKET_TYPE_ATTACH] = "ATTACH",
+ [VSOCK_PACKET_TYPE_WROTE] = "WROTE",
+ [VSOCK_PACKET_TYPE_READ] = "READ",
+ [VSOCK_PACKET_TYPE_RST] = "RST",
+ [VSOCK_PACKET_TYPE_SHUTDOWN] = "SHUTDOWN",
+ [VSOCK_PACKET_TYPE_WAITING_WRITE] = "WAITING_WRITE",
+ [VSOCK_PACKET_TYPE_WAITING_READ] = "WAITING_READ",
+ [VSOCK_PACKET_TYPE_REQUEST2] = "REQUEST2",
+ [VSOCK_PACKET_TYPE_NEGOTIATE2] = "NEGOTIATE2",
+ };
+
+ written = snprintf(cur, left, "PKT: %u:%u -> %u:%u",
+ pkt->dg.src.context, pkt->src_port,
+ pkt->dg.dst.context, pkt->dst_port);
+ if (written >= left)
+ goto error;
+
+ left -= written;
+ cur += written;
+
+ switch (pkt->type) {
+ case VSOCK_PACKET_TYPE_REQUEST:
+ case VSOCK_PACKET_TYPE_NEGOTIATE:
+ written = snprintf(cur, left, ", %s, size = %" FMT64 "u",
+ type_strings[pkt->type], pkt->u.size);
+ break;
+
+ case VSOCK_PACKET_TYPE_OFFER:
+ case VSOCK_PACKET_TYPE_ATTACH:
+ written = snprintf(cur, left, ", %s, handle = %u:%u",
+ type_strings[pkt->type],
+ pkt->u.handle.context,
+ pkt->u.handle.resource);
+ break;
+
+ case VSOCK_PACKET_TYPE_WROTE:
+ case VSOCK_PACKET_TYPE_READ:
+ case VSOCK_PACKET_TYPE_RST:
+ written = snprintf(cur, left, ", %s", type_strings[pkt->type]);
+ break;
+ case VSOCK_PACKET_TYPE_SHUTDOWN: {
+ bool recv;
+ bool send;
+
+ recv = pkt->u.mode & RCV_SHUTDOWN;
+ send = pkt->u.mode & SEND_SHUTDOWN;
+ written = snprintf(cur, left, ", %s, mode = %c%c",
+ type_strings[pkt->type],
+ recv ? 'R' : ' ', send ? 'S' : ' ');
+ }
+ break;
+
+ case VSOCK_PACKET_TYPE_WAITING_WRITE:
+ case VSOCK_PACKET_TYPE_WAITING_READ:
+ written = snprintf(cur, left,
+ ", %s, generation = %" FMT64 "u, offset = %" FMT64 "u",
+ type_strings[pkt->type],
+ pkt->u.wait.generation, pkt->u.wait.offset);
+
+ break;
+
+ case VSOCK_PACKET_TYPE_REQUEST2:
+ case VSOCK_PACKET_TYPE_NEGOTIATE2:
+ written = snprintf(cur, left,
+ ", %s, size = %" FMT64 "u, proto = %u",
+ type_strings[pkt->type], pkt->u.size,
+ pkt->proto);
+ break;
+
+ default:
+ written = snprintf(cur, left, ", unrecognized type");
+ }
+
+ if (written >= left)
+ goto error;
+
+ left -= written;
+ cur += written;
+
+ written = snprintf(cur, left, " [%s:%u]\n", function, line);
+ if (written >= left)
+ goto error;
+
+ return;
+
+error:
+ pr_err("could not log packet\n");
+}
+
+void vsock_vmci_init_tables(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(vsock_bind_table); i++)
+ INIT_LIST_HEAD(&vsock_bind_table[i]);
+
+ for (i = 0; i < ARRAY_SIZE(vsock_connected_table); i++)
+ INIT_LIST_HEAD(&vsock_connected_table[i]);
+}
+
+void __vsock_vmci_insert_bound(struct list_head *list, struct sock *sk)
+{
+ struct vsock_vmci_sock *vsk = vsock_sk(sk);
+
+ sock_hold(sk);
+ list_add(&vsk->bound_table, list);
+}
+
+void __vsock_vmci_insert_connected(struct list_head *list, struct sock *sk)
+{
+ struct vsock_vmci_sock *vsk = vsock_sk(sk);
+
+ sock_hold(sk);
+ list_add(&vsk->connected_table, list);
+}
+
+void __vsock_vmci_remove_bound(struct sock *sk)
+{
+ struct vsock_vmci_sock *vsk;
+
+ vsk = vsock_sk(sk);
+
+ list_del_init(&vsk->bound_table);
+ sock_put(sk);
+}
+
+void __vsock_vmci_remove_connected(struct sock *sk)
+{
+ struct vsock_vmci_sock *vsk;
+
+ vsk = vsock_sk(sk);
+
+ list_del_init(&vsk->connected_table);
+ sock_put(sk);
+}
+
+struct sock *__vsock_vmci_find_bound_socket(struct sockaddr_vm *addr)
+{
+ struct vsock_vmci_sock *vsk;
+
+ list_for_each_entry(vsk, vsock_bound_sockets(addr), bound_table) {
+ if (vsock_addr_equals_addr_any(addr, &vsk->local_addr))
+ return sk_vsock(vsk);
+ }
+
+ return NULL;
+}
+
+struct sock *__vsock_vmci_find_connected_socket(struct sockaddr_vm *src,
+ struct sockaddr_vm *dst)
+{
+ struct vsock_vmci_sock *vsk;
+
+ list_for_each_entry(vsk, vsock_connected_sockets(src, dst),
+ connected_table) {
+ if (vsock_addr_equals_addr(src, &vsk->remote_addr)
+ && vsock_addr_equals_addr(dst, &vsk->local_addr)) {
+ return sk_vsock(vsk);
+ }
+ }
+
+ return NULL;
+}
+
+bool __vsock_vmci_in_bound_table(struct sock *sk)
+{
+ struct vsock_vmci_sock *vsk = vsock_sk(sk);
+
+ return !list_empty(&vsk->bound_table);
+}
+
+bool __vsock_vmci_in_connected_table(struct sock *sk)
+{
+ struct vsock_vmci_sock *vsk = vsock_sk(sk);
+
+ return !list_empty(&vsk->connected_table);
+}
+
+struct sock *vsock_vmci_get_pending(struct sock *listener,
+ struct vsock_packet *pkt)
+{
+ struct vsock_vmci_sock *vlistener;
+ struct vsock_vmci_sock *vpending;
+ struct sock *pending;
+
+ vlistener = vsock_sk(listener);
+
+ list_for_each_entry(vpending, &vlistener->pending_links,
+ pending_links) {
+ struct sockaddr_vm src;
+ struct sockaddr_vm dst;
+
+ vsock_addr_init(&src, pkt->dg.src.context, pkt->src_port);
+ vsock_addr_init(&dst, pkt->dg.dst.context, pkt->dst_port);
+
+ if (vsock_addr_equals_addr(&src, &vpending->remote_addr) &&
+ vsock_addr_equals_addr(&dst, &vpending->local_addr)) {
+ pending = sk_vsock(vpending);
+ sock_hold(pending);
+ goto found;
+ }
+ }
+
+ pending = NULL;
+found:
+ return pending;
+
+}
+
+void vsock_vmci_release_pending(struct sock *pending)
+{
+ sock_put(pending);
+}
+
+void vsock_vmci_add_pending(struct sock *listener, struct sock *pending)
+{
+ struct vsock_vmci_sock *vlistener;
+ struct vsock_vmci_sock *vpending;
+
+ vlistener = vsock_sk(listener);
+ vpending = vsock_sk(pending);
+
+ sock_hold(pending);
+ sock_hold(listener);
+ list_add_tail(&vpending->pending_links, &vlistener->pending_links);
+}
+
+void vsock_vmci_remove_pending(struct sock *listener, struct sock *pending)
+{
+ struct vsock_vmci_sock *vpending = vsock_sk(pending);
+
+ list_del_init(&vpending->pending_links);
+ sock_put(listener);
+ sock_put(pending);
+}
+
+void vsock_vmci_enqueue_accept(struct sock *listener, struct sock *connected)
+{
+ struct vsock_vmci_sock *vlistener;
+ struct vsock_vmci_sock *vconnected;
+
+ vlistener = vsock_sk(listener);
+ vconnected = vsock_sk(connected);
+
+ sock_hold(connected);
+ sock_hold(listener);
+ list_add_tail(&vconnected->accept_queue, &vlistener->accept_queue);
+}
+
+struct sock *vsock_vmci_dequeue_accept(struct sock *listener)
+{
+ struct vsock_vmci_sock *vlistener;
+ struct vsock_vmci_sock *vconnected;
+
+ vlistener = vsock_sk(listener);
+
+ if (list_empty(&vlistener->accept_queue))
+ return NULL;
+
+ vconnected = list_entry(vlistener->accept_queue.next,
+ struct vsock_vmci_sock, accept_queue);
+
+ list_del_init(&vconnected->accept_queue);
+ sock_put(listener);
+ /* The caller will need a reference on the connected socket so we let
+ * it call sock_put().
+ */
+
+ return sk_vsock(vconnected);
+}
+
+void vsock_vmci_remove_accept(struct sock *listener, struct sock *connected)
+{
+ struct vsock_vmci_sock *vconnected;
+
+ if (!vsock_vmci_in_accept_queue(connected))
+ return;
+
+ vconnected = vsock_sk(connected);
+
+ list_del_init(&vconnected->accept_queue);
+ sock_put(listener);
+ sock_put(connected);
+}
+
+bool vsock_vmci_in_accept_queue(struct sock *sk)
+{
+ /* If our accept queue isn't empty, it means we're linked into some
+ * listener socket's accept queue.
+ */
+ return !vsock_vmci_is_accept_queue_empty(sk);
+}
+
+bool vsock_vmci_is_accept_queue_empty(struct sock *sk)
+{
+ struct vsock_vmci_sock *vsk = vsock_sk(sk);
+ return list_empty(&vsk->accept_queue);
+}
+
+bool vsock_vmci_is_pending(struct sock *sk)
+{
+ struct vsock_vmci_sock *vsk = vsock_sk(sk);
+ return !list_empty(&vsk->pending_links);
+}
diff --git a/net/vmw_vsock/util.h b/net/vmw_vsock/util.h
new file mode 100644
index 0000000..aef5da3
--- /dev/null
+++ b/net/vmw_vsock/util.h
@@ -0,0 +1,187 @@
+/*
+ * VMware vSockets Driver
+ *
+ * Copyright (C) 2007-2012 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef __UTIL_H__
+#define __UTIL_H__
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/stddef.h>
+#include <net/sock.h>
+
+#include "vsock_common.h"
+#include "vsock_packet.h"
+
+/* Each bound VSocket is stored in the bind hash table and each connected
+ * VSocket is stored in the connected hash table.
+ *
+ * Unbound sockets are all put on the same list attached to the end of the hash
+ * table (vsock_unbound_sockets). Bound sockets are added to the hash table in
+ * the bucket that their local address hashes to (vsock_bound_sockets(addr)
+ * represents the list that addr hashes to).
+ *
+ * Specifically, we initialize the vsock_bind_table array to a size of
+ * VSOCK_HASH_SIZE + 1 so that vsock_bind_table[0] through
+ * vsock_bind_table[VSOCK_HASH_SIZE - 1] are for bound sockets and
+ * vsock_bind_table[VSOCK_HASH_SIZE] is for unbound sockets. The hash function
+ * mods with VSOCK_HASH_SIZE - 1 to ensure this.
+ */
+#define VSOCK_HASH_SIZE 251
+#define LAST_RESERVED_PORT 1023
+#define MAX_PORT_RETRIES 24
+
+extern struct list_head vsock_bind_table[VSOCK_HASH_SIZE + 1];
+extern struct list_head vsock_connected_table[VSOCK_HASH_SIZE];
+
+extern spinlock_t vsock_table_lock;
+
+#define VSOCK_HASH(addr) ((addr)->svm_port % (VSOCK_HASH_SIZE - 1))
+#define vsock_bound_sockets(addr) (&vsock_bind_table[VSOCK_HASH(addr)])
+#define vsock_unbound_sockets (&vsock_bind_table[VSOCK_HASH_SIZE])
+
+/* XXX This can probably be implemented in a better way. */
+#define VSOCK_CONN_HASH(src, dst) \
+ (((src)->svm_cid ^ (dst)->svm_port) % (VSOCK_HASH_SIZE - 1))
+#define vsock_connected_sockets(src, dst) \
+ (&vsock_connected_table[VSOCK_CONN_HASH(src, dst)])
+#define vsock_connected_sockets_vsk(vsk) \
+ vsock_connected_sockets(&(vsk)->remote_addr, &(vsk)->local_addr)
+
+void vsock_vmci_log_pkt(char const *function, u32 line,
+ struct vsock_packet *pkt);
+
+void vsock_vmci_init_tables(void);
+void __vsock_vmci_insert_bound(struct list_head *list, struct sock *sk);
+void __vsock_vmci_insert_connected(struct list_head *list, struct sock *sk);
+void __vsock_vmci_remove_bound(struct sock *sk);
+void __vsock_vmci_remove_connected(struct sock *sk);
+struct sock *__vsock_vmci_find_bound_socket(struct sockaddr_vm *addr);
+struct sock *__vsock_vmci_find_connected_socket(struct sockaddr_vm *src,
+ struct sockaddr_vm *dst);
+bool __vsock_vmci_in_bound_table(struct sock *sk);
+bool __vsock_vmci_in_connected_table(struct sock *sk);
+
+struct sock *vsock_vmci_get_pending(struct sock *listener,
+ struct vsock_packet *pkt);
+void vsock_vmci_release_pending(struct sock *pending);
+void vsock_vmci_add_pending(struct sock *listener, struct sock *pending);
+void vsock_vmci_remove_pending(struct sock *listener, struct sock *pending);
+void vsock_vmci_enqueue_accept(struct sock *listener, struct sock *connected);
+struct sock *vsock_vmci_dequeue_accept(struct sock *listener);
+void vsock_vmci_remove_accept(struct sock *listener, struct sock *connected);
+bool vsock_vmci_in_accept_queue(struct sock *sk);
+bool vsock_vmci_is_accept_queue_empty(struct sock *sk);
+bool vsock_vmci_is_pending(struct sock *sk);
+
+static inline void vsock_vmci_insert_bound(struct list_head *list,
+ struct sock *sk);
+static inline void vsock_vmci_insert_connected(struct list_head *list,
+ struct sock *sk);
+static inline void vsock_vmci_remove_bound(struct sock *sk);
+static inline void vsock_vmci_remove_connected(struct sock *sk);
+static inline struct sock *vsock_vmci_find_bound_socket(struct sockaddr_vm
+ *addr);
+static inline struct sock *vsock_vmci_find_connected_socket(struct sockaddr_vm
+ *src,
+ struct sockaddr_vm
+ *dst);
+static inline bool vsock_vmci_in_bound_table(struct sock *sk);
+static inline bool vsock_vmci_in_connected_table(struct sock *sk);
+
+static inline void
+vsock_vmci_insert_bound(struct list_head *list, struct sock *sk)
+{
+ spin_lock_bh(&vsock_table_lock);
+ __vsock_vmci_insert_bound(list, sk);
+ spin_unlock_bh(&vsock_table_lock);
+}
+
+static inline void
+vsock_vmci_insert_connected(struct list_head *list, struct sock *sk)
+{
+ spin_lock_bh(&vsock_table_lock);
+ __vsock_vmci_insert_connected(list, sk);
+ spin_unlock_bh(&vsock_table_lock);
+}
+
+static inline void vsock_vmci_remove_bound(struct sock *sk)
+{
+ spin_lock_bh(&vsock_table_lock);
+ __vsock_vmci_remove_bound(sk);
+ spin_unlock_bh(&vsock_table_lock);
+}
+
+static inline void vsock_vmci_remove_connected(struct sock *sk)
+{
+ spin_lock_bh(&vsock_table_lock);
+ __vsock_vmci_remove_connected(sk);
+ spin_unlock_bh(&vsock_table_lock);
+}
+
+static inline struct sock *vsock_vmci_find_bound_socket(struct sockaddr_vm
+ *addr)
+{
+ struct sock *sk;
+
+ spin_lock_bh(&vsock_table_lock);
+ sk = __vsock_vmci_find_bound_socket(addr);
+ if (sk)
+ sock_hold(sk);
+
+ spin_unlock_bh(&vsock_table_lock);
+
+ return sk;
+}
+
+static inline struct sock *vsock_vmci_find_connected_socket(struct sockaddr_vm
+ *src,
+ struct sockaddr_vm
+ *dst)
+{
+ struct sock *sk;
+
+ spin_lock_bh(&vsock_table_lock);
+ sk = __vsock_vmci_find_connected_socket(src, dst);
+ if (sk)
+ sock_hold(sk);
+
+ spin_unlock_bh(&vsock_table_lock);
+
+ return sk;
+}
+
+static inline bool vsock_vmci_in_bound_table(struct sock *sk)
+{
+ bool ret;
+
+ spin_lock_bh(&vsock_table_lock);
+ ret = __vsock_vmci_in_bound_table(sk);
+ spin_unlock_bh(&vsock_table_lock);
+
+ return ret;
+}
+
+static inline bool vsock_vmci_in_connected_table(struct sock *sk)
+{
+ bool ret;
+
+ spin_lock_bh(&vsock_table_lock);
+ ret = __vsock_vmci_in_connected_table(sk);
+ spin_unlock_bh(&vsock_table_lock);
+
+ return ret;
+}
+
+#endif /* __UTIL_H__ */
^ permalink raw reply related
* [PATCH 6/6] VSOCK: header and config files.
From: George Zhang @ 2013-01-09 0:00 UTC (permalink / raw)
To: netdev, linux-kernel, georgezhang, virtualization
Cc: pv-drivers, gregkh, davem
In-Reply-To: <20130108235633.3719.6085.stgit@promb-2n-dhcp175.eng.vmware.com>
VSOCK header files, Makefiles and Kconfig systems for Linux VSocket module.
Signed-off-by: George Zhang <georgezhang@vmware.com>
Acked-by: Andy king <acking@vmware.com>
Acked-by: Dmitry Torokhov <dtor@vmware.com>
---
Documentation/ioctl/ioctl-number.txt | 1
include/linux/socket.h | 4
net/Kconfig | 1
net/Makefile | 1
net/vmw_vsock/Kconfig | 14 +
net/vmw_vsock/Makefile | 4
net/vmw_vsock/notify_qstate.c | 408 ++++++++++++++++++++++++++++++++++
net/vmw_vsock/vmci_sockets.h | 270 +++++++++++++++++++++++
net/vmw_vsock/vmci_sockets_packet.h | 79 +++++++
net/vmw_vsock/vsock_common.h | 103 +++++++++
net/vmw_vsock/vsock_packet.h | 92 ++++++++
net/vmw_vsock/vsock_version.h | 22 ++
12 files changed, 998 insertions(+), 1 deletions(-)
create mode 100644 net/vmw_vsock/Kconfig
create mode 100644 net/vmw_vsock/Makefile
create mode 100644 net/vmw_vsock/notify_qstate.c
create mode 100644 net/vmw_vsock/vmci_sockets.h
create mode 100644 net/vmw_vsock/vmci_sockets_packet.h
create mode 100644 net/vmw_vsock/vsock_common.h
create mode 100644 net/vmw_vsock/vsock_packet.h
create mode 100644 net/vmw_vsock/vsock_version.h
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index 2152b0e..df2b341 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -70,6 +70,7 @@ Code Seq#(hex) Include File Comments
0x03 all linux/hdreg.h
0x04 D2-DC linux/umsdos_fs.h Dead since 2.6.11, but don't reuse these.
0x06 all linux/lp.h
+0x07 9F-D0 linux/vmw_vmci_defs.h <mailto:georgezhang@vmware.com>
0x09 all linux/raid/md_u.h
0x10 00-0F drivers/char/s390/vmcp.h
0x12 all linux/fs.h
diff --git a/include/linux/socket.h b/include/linux/socket.h
index 9a546ff..2c57d63 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -178,7 +178,8 @@ struct ucred {
#define AF_CAIF 37 /* CAIF sockets */
#define AF_ALG 38 /* Algorithm sockets */
#define AF_NFC 39 /* NFC sockets */
-#define AF_MAX 40 /* For now.. */
+#define AF_VSOCK 40 /* VMCI sockets */
+#define AF_MAX 41 /* For now.. */
/* Protocol families, same as address families. */
#define PF_UNSPEC AF_UNSPEC
@@ -221,6 +222,7 @@ struct ucred {
#define PF_CAIF AF_CAIF
#define PF_ALG AF_ALG
#define PF_NFC AF_NFC
+#define PF_VSOCK AF_VSOCK
#define PF_MAX AF_MAX
/* Maximum queue length specifiable by listen. */
diff --git a/net/Kconfig b/net/Kconfig
index 30b48f5..f143ac3 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -218,6 +218,7 @@ source "net/dcb/Kconfig"
source "net/dns_resolver/Kconfig"
source "net/batman-adv/Kconfig"
source "net/openvswitch/Kconfig"
+source "net/vmw_vsock/Kconfig"
config RPS
boolean
diff --git a/net/Makefile b/net/Makefile
index 4f4ee08..cae59f4 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -70,3 +70,4 @@ obj-$(CONFIG_CEPH_LIB) += ceph/
obj-$(CONFIG_BATMAN_ADV) += batman-adv/
obj-$(CONFIG_NFC) += nfc/
obj-$(CONFIG_OPENVSWITCH) += openvswitch/
+obj-$(CONFIG_VMWARE_VSOCK) += vmw_vsock/
diff --git a/net/vmw_vsock/Kconfig b/net/vmw_vsock/Kconfig
new file mode 100644
index 0000000..95e2568
--- /dev/null
+++ b/net/vmw_vsock/Kconfig
@@ -0,0 +1,14 @@
+#
+# Vsock protocol
+#
+
+config VMWARE_VSOCK
+ tristate "Virtual Socket protocol"
+ depends on VMWARE_VMCI
+ help
+ Virtual Socket Protocol is a socket protocol similar to TCP/IP
+ allowing comunication between Virtual Machines and VMware
+ hypervisor.
+
+ To compile this driver as a module, choose M here: the module
+ will be called vsock. If unsure, say N.
diff --git a/net/vmw_vsock/Makefile b/net/vmw_vsock/Makefile
new file mode 100644
index 0000000..4e940fe
--- /dev/null
+++ b/net/vmw_vsock/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_VMWARE_VSOCK) += vmw_vsock.o
+
+vmw_vsock-y += af_vsock.o notify.o notify_qstate.o stats.o util.o \
+ vsock_addr.o
diff --git a/net/vmw_vsock/notify_qstate.c b/net/vmw_vsock/notify_qstate.c
new file mode 100644
index 0000000..1132ae4
--- /dev/null
+++ b/net/vmw_vsock/notify_qstate.c
@@ -0,0 +1,408 @@
+/*
+ * VMware vSockets Driver
+ *
+ * Copyright (C) 2009-2012 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/stddef.h>
+#include <net/sock.h>
+
+#include "notify.h"
+#include "af_vsock.h"
+
+#define PKT_FIELD(vsk, field_name) ((vsk)->notify.pkt_q_state.field_name)
+
+static bool vsock_vmci_notify_waiting_write(struct vsock_vmci_sock *vsk)
+{
+ bool retval;
+ u64 notify_limit;
+
+ if (!PKT_FIELD(vsk, peer_waiting_write))
+ return false;
+
+ /* When the sender blocks, we take that as a sign that the sender is
+ * faster than the receiver. To reduce the transmit rate of the sender,
+ * we delay the sending of the read notification by decreasing the
+ * write_notify_window. The notification is delayed until the number of
+ * bytes used in the queue drops below the write_notify_window.
+ */
+
+ if (!PKT_FIELD(vsk, peer_waiting_write_detected)) {
+ PKT_FIELD(vsk, peer_waiting_write_detected) = true;
+ if (PKT_FIELD(vsk, write_notify_window) < PAGE_SIZE) {
+ PKT_FIELD(vsk, write_notify_window) =
+ PKT_FIELD(vsk, write_notify_min_window);
+ } else {
+ PKT_FIELD(vsk, write_notify_window) -= PAGE_SIZE;
+ if (PKT_FIELD(vsk, write_notify_window) <
+ PKT_FIELD(vsk, write_notify_min_window))
+ PKT_FIELD(vsk, write_notify_window) =
+ PKT_FIELD(vsk, write_notify_min_window);
+
+ }
+ }
+ notify_limit = vsk->consume_size - PKT_FIELD(vsk, write_notify_window);
+
+ /* The notify_limit is used to delay notifications in the case where
+ * flow control is enabled. Below the test is expressed in terms of
+ * free space in the queue: if free_space > ConsumeSize -
+ * write_notify_window then notify An alternate way of expressing this
+ * is to rewrite the expression to use the data ready in the receive
+ * queue: if write_notify_window > bufferReady then notify as
+ * free_space == ConsumeSize - bufferReady.
+ */
+
+ retval = vmci_qpair_consume_free_space(vsk->qpair) > notify_limit;
+
+ if (retval) {
+ /* Once we notify the peer, we reset the detected flag so the
+ * next wait will again cause a decrease in the window size.
+ */
+
+ PKT_FIELD(vsk, peer_waiting_write_detected) = false;
+ }
+ return retval;
+}
+
+static void
+vsock_vmci_handle_read(struct sock *sk,
+ struct vsock_packet *pkt,
+ bool bottom_half,
+ struct sockaddr_vm *dst, struct sockaddr_vm *src)
+{
+
+ sk->sk_write_space(sk);
+}
+
+static void
+vsock_vmci_handle_wrote(struct sock *sk,
+ struct vsock_packet *pkt,
+ bool bottom_half,
+ struct sockaddr_vm *dst, struct sockaddr_vm *src)
+{
+ sk->sk_data_ready(sk, 0);
+}
+
+static void vsock_vmci_block_update_write_window(struct sock *sk)
+{
+ struct vsock_vmci_sock *vsk;
+
+ vsk = vsock_sk(sk);
+
+ if (PKT_FIELD(vsk, write_notify_window) < vsk->consume_size)
+ PKT_FIELD(vsk, write_notify_window) =
+ min(PKT_FIELD(vsk, write_notify_window) + PAGE_SIZE,
+ vsk->consume_size);
+
+}
+
+static int vsock_vmci_send_read_notification(struct sock *sk)
+{
+ struct vsock_vmci_sock *vsk;
+ bool sent_read;
+ unsigned int retries;
+ int err;
+
+ vsk = vsock_sk(sk);
+ sent_read = false;
+ retries = 0;
+ err = 0;
+
+ if (vsock_vmci_notify_waiting_write(vsk)) {
+ /* Notify the peer that we have read, retrying the send on
+ * failure up to our maximum value. XXX For now we just log
+ * the failure, but later we should schedule a work item to
+ * handle the resend until it succeeds. That would require
+ * keeping track of work items in the vsk and cleaning them up
+ * upon socket close.
+ */
+ while (!(vsk->peer_shutdown & RCV_SHUTDOWN) &&
+ !sent_read && retries < VSOCK_MAX_DGRAM_RESENDS) {
+ err = VSOCK_SEND_READ(sk);
+ if (err >= 0)
+ sent_read = true;
+
+ retries++;
+ }
+
+ if (retries >= VSOCK_MAX_DGRAM_RESENDS && !sent_read)
+ pr_err("%p unable to send read notification to peer\n",
+ sk);
+ else
+ PKT_FIELD(vsk, peer_waiting_write) = false;
+
+ }
+ return err;
+}
+
+static void vsock_vmci_notify_pkt_socket_init(struct sock *sk)
+{
+ struct vsock_vmci_sock *vsk;
+ vsk = vsock_sk(sk);
+
+ PKT_FIELD(vsk, write_notify_window) = PAGE_SIZE;
+ PKT_FIELD(vsk, write_notify_min_window) = PAGE_SIZE;
+ PKT_FIELD(vsk, peer_waiting_write) = false;
+ PKT_FIELD(vsk, peer_waiting_write_detected) = false;
+}
+
+static void vsock_vmci_notify_pkt_socket_destruct(struct sock *sk)
+{
+ struct vsock_vmci_sock *vsk;
+ vsk = vsock_sk(sk);
+
+ PKT_FIELD(vsk, write_notify_window) = PAGE_SIZE;
+ PKT_FIELD(vsk, write_notify_min_window) = PAGE_SIZE;
+ PKT_FIELD(vsk, peer_waiting_write) = false;
+ PKT_FIELD(vsk, peer_waiting_write_detected) = false;
+}
+
+static int
+vsock_vmci_notify_pkt_poll_in(struct sock *sk,
+ size_t target, bool *data_ready_now)
+{
+ struct vsock_vmci_sock *vsk = vsock_sk(sk);
+
+ if (vsock_vmci_stream_has_data(vsk)) {
+ *data_ready_now = true;
+ } else {
+ /* We can't read right now because there is nothing in the
+ * queue. Ask for notifications when there is something to
+ * read.
+ */
+ if (sk->sk_state == SS_CONNECTED)
+ vsock_vmci_block_update_write_window(sk);
+
+ *data_ready_now = false;
+ }
+
+ return 0;
+}
+
+static int
+vsock_vmci_notify_pkt_poll_out(struct sock *sk,
+ size_t target, bool *space_avail_now)
+{
+ s64 produce_q_free_space;
+ struct vsock_vmci_sock *vsk = vsock_sk(sk);
+
+ produce_q_free_space = vsock_vmci_stream_has_space(vsk);
+ if (produce_q_free_space > 0) {
+ *space_avail_now = true;
+ return 0;
+ } else if (produce_q_free_space == 0) {
+ /* This is a connected socket but we can't currently send data.
+ * Nothing else to do.
+ */
+ *space_avail_now = false;
+ }
+
+ return 0;
+}
+
+static int
+vsock_vmci_notify_pkt_recv_init(struct sock *sk,
+ size_t target,
+ struct vsock_vmci_recv_notify_data *data)
+{
+ struct vsock_vmci_sock *vsk = vsock_sk(sk);
+
+ data->consume_head = 0;
+ data->produce_tail = 0;
+ data->notify_on_block = false;
+
+ if (PKT_FIELD(vsk, write_notify_min_window) < target + 1) {
+ PKT_FIELD(vsk, write_notify_min_window) = target + 1;
+ if (PKT_FIELD(vsk, write_notify_window) <
+ PKT_FIELD(vsk, write_notify_min_window)) {
+ /* If the current window is smaller than the new
+ * minimal window size, we need to reevaluate whether
+ * we need to notify the sender. If the number of ready
+ * bytes are smaller than the new window, we need to
+ * send a notification to the sender before we block.
+ */
+
+ PKT_FIELD(vsk, write_notify_window) =
+ PKT_FIELD(vsk, write_notify_min_window);
+ data->notify_on_block = true;
+ }
+ }
+
+ return 0;
+}
+
+static int
+vsock_vmci_notify_pkt_recv_pre_block(struct sock *sk,
+ size_t target,
+ struct vsock_vmci_recv_notify_data *data)
+{
+ int err = 0;
+
+ vsock_vmci_block_update_write_window(sk);
+
+ if (data->notify_on_block) {
+ err = vsock_vmci_send_read_notification(sk);
+ if (err < 0)
+ return err;
+
+ data->notify_on_block = false;
+ }
+
+ return err;
+}
+
+static int
+vsock_vmci_notify_pkt_recv_post_dequeue(struct sock *sk,
+ size_t target,
+ ssize_t copied,
+ bool data_read,
+ struct vsock_vmci_recv_notify_data *data)
+{
+ struct vsock_vmci_sock *vsk;
+ int err;
+ bool was_full = false;
+ u64 free_space;
+
+ vsk = vsock_sk(sk);
+ err = 0;
+
+ if (data_read) {
+ smp_mb();
+
+ free_space = vmci_qpair_consume_free_space(vsk->qpair);
+ was_full = free_space == copied;
+
+ if (was_full)
+ PKT_FIELD(vsk, peer_waiting_write) = true;
+
+ err = vsock_vmci_send_read_notification(sk);
+ if (err < 0)
+ return err;
+
+ /* See the comment in vsock_vmci_notify_pkt_send_post_enqueue */
+ sk->sk_data_ready(sk, 0);
+ }
+
+ return err;
+}
+
+static int
+vsock_vmci_notify_pkt_send_init(struct sock *sk,
+ struct vsock_vmci_send_notify_data *data)
+{
+ data->consume_head = 0;
+ data->produce_tail = 0;
+
+ return 0;
+}
+
+static int
+vsock_vmci_notify_pkt_send_post_enqueue(struct sock *sk,
+ ssize_t written,
+ struct vsock_vmci_send_notify_data *data)
+{
+ int err = 0;
+ struct vsock_vmci_sock *vsk;
+ bool sent_wrote = false;
+ bool was_empty;
+ int retries = 0;
+
+ vsk = vsock_sk(sk);
+
+ smp_mb();
+
+ was_empty = (vmci_qpair_produce_buf_ready(vsk->qpair) == written);
+ if (was_empty) {
+ while (!(vsk->peer_shutdown & RCV_SHUTDOWN) &&
+ !sent_wrote && retries < VSOCK_MAX_DGRAM_RESENDS) {
+ err = VSOCK_SEND_WROTE(sk);
+ if (err >= 0)
+ sent_wrote = true;
+
+ retries++;
+ }
+ }
+
+ if (retries >= VSOCK_MAX_DGRAM_RESENDS && !sent_wrote) {
+ pr_err("%p unable to send wrote notification to peer\n",
+ sk);
+ return err;
+ }
+
+ return err;
+}
+
+static void
+vsock_vmci_notify_pkt_handle_pkt(struct sock *sk,
+ struct vsock_packet *pkt,
+ bool bottom_half,
+ struct sockaddr_vm *dst,
+ struct sockaddr_vm *src, bool *pkt_processed)
+{
+ bool processed = false;
+
+ switch (pkt->type) {
+ case VSOCK_PACKET_TYPE_WROTE:
+ vsock_vmci_handle_wrote(sk, pkt, bottom_half, dst, src);
+ processed = true;
+ break;
+ case VSOCK_PACKET_TYPE_READ:
+ vsock_vmci_handle_read(sk, pkt, bottom_half, dst, src);
+ processed = true;
+ break;
+ }
+
+ if (pkt_processed)
+ *pkt_processed = processed;
+
+}
+
+static void vsock_vmci_notify_pkt_process_request(struct sock *sk)
+{
+ struct vsock_vmci_sock *vsk = vsock_sk(sk);
+
+ PKT_FIELD(vsk, write_notify_window) = vsk->consume_size;
+ if (vsk->consume_size < PKT_FIELD(vsk, write_notify_min_window))
+ PKT_FIELD(vsk, write_notify_min_window) = vsk->consume_size;
+
+}
+
+static void vsock_vmci_notify_pkt_process_negotiate(struct sock *sk)
+{
+ struct vsock_vmci_sock *vsk = vsock_sk(sk);
+
+ PKT_FIELD(vsk, write_notify_window) = vsk->consume_size;
+ if (vsk->consume_size < PKT_FIELD(vsk, write_notify_min_window))
+ PKT_FIELD(vsk, write_notify_min_window) = vsk->consume_size;
+
+}
+
+/* Socket always on control packet based operations. */
+struct vsock_vmci_notify_ops vsock_vmci_notify_pkt_q_state_ops = {
+ vsock_vmci_notify_pkt_socket_init,
+ vsock_vmci_notify_pkt_socket_destruct,
+ vsock_vmci_notify_pkt_poll_in,
+ vsock_vmci_notify_pkt_poll_out,
+ vsock_vmci_notify_pkt_handle_pkt,
+ vsock_vmci_notify_pkt_recv_init,
+ vsock_vmci_notify_pkt_recv_pre_block,
+ NULL, /* recv_pre_dequeue */
+ vsock_vmci_notify_pkt_recv_post_dequeue,
+ vsock_vmci_notify_pkt_send_init,
+ NULL, /* send_pre_block */
+ NULL, /* send_pre_enqueue */
+ vsock_vmci_notify_pkt_send_post_enqueue,
+ vsock_vmci_notify_pkt_process_request,
+ vsock_vmci_notify_pkt_process_negotiate,
+};
diff --git a/net/vmw_vsock/vmci_sockets.h b/net/vmw_vsock/vmci_sockets.h
new file mode 100644
index 0000000..b08b114
--- /dev/null
+++ b/net/vmw_vsock/vmci_sockets.h
@@ -0,0 +1,270 @@
+/*
+ * VMware vSockets Driver
+ *
+ * Copyright (C) 2007-2012 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _VMCI_SOCKETS_H_
+#define _VMCI_SOCKETS_H_
+
+#if !defined(__KERNEL__)
+#include <sys/socket.h>
+#endif
+
+/* Option name for STREAM socket buffer size. Use as the option name in
+ * setsockopt(3) or getsockopt(3) to set or get an unsigned long long that
+ * specifies the size of the buffer underlying a vSockets STREAM socket.
+ * Value is clamped to the MIN and MAX.
+ */
+
+#define SO_VMCI_BUFFER_SIZE 0
+
+/* Option name for STREAM socket minimum buffer size. Use as the option name
+ * in setsockopt(3) or getsockopt(3) to set or get an unsigned long long that
+ * specifies the minimum size allowed for the buffer underlying a vSockets
+ * STREAM socket.
+ */
+
+#define SO_VMCI_BUFFER_MIN_SIZE 1
+
+/* Option name for STREAM socket maximum buffer size. Use as the option name
+ * in setsockopt(3) or getsockopt(3) to set or get an unsigned long long
+ * that specifies the maximum size allowed for the buffer underlying a
+ * vSockets STREAM socket.
+ */
+
+#define SO_VMCI_BUFFER_MAX_SIZE 2
+
+/* Option name for socket peer's host-specific VM ID. Use as the option name
+ * in getsockopt(3) to get a host-specific identifier for the peer endpoint's
+ * VM. The identifier is a signed integer.
+ * Only available for hypervisor endpoints.
+ */
+
+#define SO_VMCI_PEER_HOST_VM_ID 3
+
+/* Option name for socket's service label. Use as the option name in
+ * setsockopt(3) or getsockopt(3) to set or get the service label for a socket.
+ * The service label is a C-style NUL-terminated string. Only available for
+ * hypervisor endpoints.
+ */
+
+#define SO_VMCI_SERVICE_LABEL 4
+
+/* Option name for determining if a socket is trusted. Use as the option name
+ * in getsockopt(3) to determine if a socket is trusted. The value is a
+ * signed integer.
+ */
+
+#define SO_VMCI_TRUSTED 5
+
+/* Option name for STREAM socket connection timeout. Use as the option name
+ * in setsockopt(3) or getsockopt(3) to set or get the connection
+ * timeout for a STREAM socket. The value is platform dependent. On ESX,
+ * Linux and Mac OS, it is a struct timeval. On Windows, it is a DWORD.
+ */
+
+#define SO_VMCI_CONNECT_TIMEOUT 6
+
+/* Option name for using non-blocking send/receive. Use as the option name
+ * for setsockopt(3) or getsockopt(3) to set or get the non-blocking
+ * transmit/receive flag for a STREAM socket. This flag determines whether
+ * send() and recv() can be called in non-blocking contexts for the given
+ * socket. The value is a signed integer.
+ *
+ * This option is only relevant to kernel endpoints, where descheduling the
+ * thread of execution is not allowed, for example, while holding a spinlock.
+ * It is not to be confused with conventional non-blocking socket operations.
+ *
+ * Only available for hypervisor endpoints.
+ */
+
+#define SO_VMCI_NONBLOCK_TXRX 7
+
+/* The vSocket equivalent of INADDR_ANY. This works for the svm_cid field of
+ * sockaddr_vm and indicates the context ID of the current endpoint.
+ */
+
+#define VMADDR_CID_ANY ((unsigned int)-1)
+
+/* Bind to any available port. Works for the svm_port field of
+ * sockaddr_vm.
+ */
+
+#define VMADDR_PORT_ANY ((unsigned int)-1)
+
+/* Invalid vSockets version. */
+
+#define VMCI_SOCKETS_INVALID_VERSION ((unsigned int)-1)
+
+/* The epoch (first) component of the vSockets version. A single byte
+ * representing the epoch component of the vSockets version.
+ */
+
+#define VMCI_SOCKETS_VERSION_EPOCH(_v) (((_v) & 0xFF000000) >> 24)
+
+/* The major (second) component of the vSockets version. A single byte
+ * representing the major component of the vSockets version. Typically
+ * changes for every major release of a product.
+ */
+
+#define VMCI_SOCKETS_VERSION_MAJOR(_v) (((_v) & 0x00FF0000) >> 16)
+
+/* The minor (third) component of the vSockets version. Two bytes representing
+ * the minor component of the vSockets version.
+ */
+
+#define VMCI_SOCKETS_VERSION_MINOR(_v) (((_v) & 0x0000FFFF))
+
+/* Address structure for vSockets. The address family should be set to
+ * whatever vmci_sock_get_af_value_fd() returns. The structure members should
+ * all align on their natural boundaries without resorting to compiler packing
+ * directives. The total size of this structure should be exactly the same as
+ * that of struct sockaddr.
+ */
+
+struct sockaddr_vm {
+ sa_family_t svm_family;
+ unsigned short svm_reserved1;
+ unsigned int svm_port;
+ unsigned int svm_cid;
+ unsigned char svm_zero[sizeof(struct sockaddr) -
+ sizeof(sa_family_t) -
+ sizeof(unsigned short) -
+ sizeof(unsigned int) - sizeof(unsigned int)];
+};
+
+#if defined(linux) && defined(__KERNEL__)
+int vmci_sock_get_local_c_id(void);
+#else
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+#include <stdio.h>
+
+#define VMCI_SOCKETS_DEFAULT_DEVICE "/dev/vsock"
+#define VMCI_SOCKETS_CLASSIC_ESX_DEVICE "/vmfs/devices/char/vsock/vsock"
+#define VMCI_SOCKETS_VERSION 1972
+#define VMCI_SOCKETS_GET_AF_VALUE 1976
+#define VMCI_SOCKETS_GET_LOCAL_CID 1977
+
+/* Returns the current version of vSockets. The version is a 32-bit unsigned
+ * integer that consist of three components: the epoch, the major version, and
+ * the minor version. Use the VMCI_SOCKETS_VERSION macros to extract the
+ * components.
+ */
+
+static inline unsigned int VMCISock_Version(void)
+{
+ int fd;
+ unsigned int version;
+
+ fd = open(VMCI_SOCKETS_DEFAULT_DEVICE, O_RDWR);
+ if (fd < 0) {
+ fd = open(VMCI_SOCKETS_CLASSIC_ESX_DEVICE, O_RDWR);
+ if (fd < 0)
+ return VMCI_SOCKETS_INVALID_VERSION;
+ }
+
+ if (ioctl(fd, VMCI_SOCKETS_VERSION, &version) < 0)
+ version = VMCI_SOCKETS_INVALID_VERSION;
+
+ close(fd);
+ return version;
+}
+
+/* Returns the value to be used for the VMCI Sockets address family. This
+ * value should be used as the domain argument to socket(2) (when you might
+ * otherwise use AF_INET). For VMCI Socket-specific options, this value
+ * should also be used for the level argument to setsockopt(2) (when you might
+ * otherwise use SOL_TCP).
+ */
+
+static inline int vmci_sock_get_af_value_fd(int *out_fd)
+{
+ int fd;
+ int family;
+
+ fd = open(VMCI_SOCKETS_DEFAULT_DEVICE, O_RDWR);
+ if (fd < 0) {
+ fd = open(VMCI_SOCKETS_CLASSIC_ESX_DEVICE, O_RDWR);
+ if (fd < 0)
+ return -1;
+ }
+
+ if (ioctl(fd, VMCI_SOCKETS_GET_AF_VALUE, &family) < 0)
+ family = -1;
+
+ if (family < 0)
+ close(fd);
+ else if (out_fd)
+ *out_fd = fd;
+
+ return family;
+}
+
+/* Retrieve the address family value for vSockets. Returns the value to be
+ * used for the VMCI Sockets address family. This value should be used as the
+ * domain argument to socket(2) (when you might otherwise use AF_INET). For
+ * VMCI Socket-specific options, this value should also be used for the level
+ * argument to setsockopt(2) (when you might otherwise use SOL_TCP).
+ *
+ * This function leaves its descriptor to the vsock device open so that the
+ * socket implementation knows that the socket family is still in use. This
+ * is done because the address family is registered with the kernel on-demand
+ * and a notification is needed to unregister the address family. Use of this
+ * function is thus discouraged; please use vmci_sock_get_af_value_fd()
+ * instead.
+ */
+
+static inline int vmci_sock_get_af_value(void)
+{
+ return vmci_sock_get_af_value_fd(NULL);
+}
+
+/* Release the file descriptor obtained when retrieving the address family
+ * value. Use this to release the file descriptor obtained by calling
+ * vmci_sock_get_af_value_fd().
+ */
+
+static inline void vmci_sock_release_af_value_fd(int fd)
+{
+ if (fd >= 0)
+ close(fd);
+}
+
+/* Retrieve the current context ID. */
+
+static inline unsigned int vmci_sock_get_local_cid(void)
+{
+ int fd;
+ unsigned int context_id;
+
+ fd = open(VMCI_SOCKETS_DEFAULT_DEVICE, O_RDWR);
+ if (fd < 0) {
+ fd = open(VMCI_SOCKETS_CLASSIC_ESX_DEVICE, O_RDWR);
+ if (fd < 0)
+ return VMADDR_CID_ANY;
+ }
+
+ if (ioctl(fd, VMCI_SOCKETS_GET_LOCAL_CID, &context_id) < 0)
+ context_id = VMADDR_CID_ANY;
+
+ close(fd);
+ return context_id;
+}
+#endif
+
+#endif
diff --git a/net/vmw_vsock/vmci_sockets_packet.h b/net/vmw_vsock/vmci_sockets_packet.h
new file mode 100644
index 0000000..1fd0805
--- /dev/null
+++ b/net/vmw_vsock/vmci_sockets_packet.h
@@ -0,0 +1,79 @@
+/*
+ * VMware vSockets Driver
+ *
+ * Copyright (C) 2012 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _VMCI_SOCKETS_PACKET_H_
+#define _VMCI_SOCKETS_PACKET_H_
+
+#include <linux/vmw_vmci_defs.h>
+#include <linux/vmw_vmci_api.h>
+
+/* If the packet format changes in a release then this should change too. */
+#define VSOCK_PACKET_VERSION 1
+
+/* The resource ID on which control packets are sent. */
+#define VSOCK_PACKET_RID 1
+
+enum vsock_packet_type {
+ VSOCK_PACKET_TYPE_INVALID = 0,
+ VSOCK_PACKET_TYPE_REQUEST,
+ VSOCK_PACKET_TYPE_NEGOTIATE,
+ VSOCK_PACKET_TYPE_OFFER,
+ VSOCK_PACKET_TYPE_ATTACH,
+ VSOCK_PACKET_TYPE_WROTE,
+ VSOCK_PACKET_TYPE_READ,
+ VSOCK_PACKET_TYPE_RST,
+ VSOCK_PACKET_TYPE_SHUTDOWN,
+ VSOCK_PACKET_TYPE_WAITING_WRITE,
+ VSOCK_PACKET_TYPE_WAITING_READ,
+ VSOCK_PACKET_TYPE_REQUEST2,
+ VSOCK_PACKET_TYPE_NEGOTIATE2,
+ VSOCK_PACKET_TYPE_MAX
+};
+
+typedef u16 vsock_proto_version;
+#define VSOCK_PROTO_INVALID 0
+#define VSOCK_PROTO_PKT_ON_NOTIFY (1 << 0)
+
+#define VSOCK_PROTO_ALL_SUPPORTED (VSOCK_PROTO_PKT_ON_NOTIFY)
+
+struct vsock_waiting_info {
+ u64 generation;
+ u64 offset;
+};
+
+/* Control packet type for STREAM sockets. DGRAMs have no control packets nor
+ * special packet header for data packets, they are just raw VMCI DGRAM
+ * messages. For STREAMs, control packets are sent over the control channel
+ * while data is written and read directly from queue pairs with no packet
+ * format.
+ */
+struct vsock_packet {
+ struct vmci_datagram dg;
+ u8 version;
+ u8 type;
+ vsock_proto_version proto;
+
+ u32 src_port;
+ u32 dst_port;
+ u32 _reserved2;
+ union {
+ u64 size;
+ u64 mode;
+ struct vmci_handle handle;
+ struct vsock_waiting_info wait;
+ } u;
+};
+
+#endif
diff --git a/net/vmw_vsock/vsock_common.h b/net/vmw_vsock/vsock_common.h
new file mode 100644
index 0000000..a7c82e4
--- /dev/null
+++ b/net/vmw_vsock/vsock_common.h
@@ -0,0 +1,103 @@
+/*
+ * VMware vSockets Driver
+ *
+ * Copyright (C) 2007-2012 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _VSOCK_COMMON_H_
+#define _VSOCK_COMMON_H_
+
+/* vmci_sock_get_af_value_int is defined separately from vmci_sock_get_af_value
+ * because it is used in several different contexts. In particular it is called
+ * from vsock_addr.c which gets compiled into both our kernel modules as well
+ * as the user level vsock library. In the linux kernel we need different
+ * behavior than external kernel modules using VMCI Sockets api inside the
+ * kernel. FIXME
+ */
+
+#if defined __KERNEL__
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <asm/page.h>
+#else
+/* In userland, just use the normal exported userlevel api. */
+#define vmci_sock_get_af_value_int() vmci_sock_get_af_value()
+#endif
+
+#include <linux/vmw_vmci_defs.h>
+#include <linux/vmw_vmci_api.h>
+
+#include "vmci_sockets.h"
+#include "vsock_addr.h"
+
+#ifdef __x86_64__
+#define FMT64 "ll"
+#else
+#define FMT64 "L"
+#endif
+
+#define MAX_UINT32 ((u32)0xffffffff)
+
+#ifndef ESYSNOTREADY
+#define ESYSNOTREADY EOPNOTSUPP
+#endif
+
+#define sockerr() errno
+#define sockerr2err(_e) (((_e) > 0) ? -(_e) : (_e))
+#define SS_LISTEN 255
+
+extern u32 vmci_get_context_id(void);
+
+/* Helper function to determine if the given handle points to the local context.
+ * Returns TRUE if the given handle is for the local context, FALSE otherwise.
+ */
+
+static inline bool vsock_vmci_is_local(struct vmci_handle handle)
+{
+ return vmci_get_context_id() == handle.context;
+}
+
+/* Helper function to convert from a VMCI error code to a VSock error code. */
+
+static inline s32 vsock_vmci_error_to_vsock_error(s32 vmci_error)
+{
+ int err;
+
+ switch (vmci_error) {
+ case VMCI_ERROR_NO_MEM:
+ err = ENOMEM;
+ break;
+ case VMCI_ERROR_DUPLICATE_ENTRY:
+ case VMCI_ERROR_ALREADY_EXISTS:
+ err = EADDRINUSE;
+ break;
+ case VMCI_ERROR_NO_ACCESS:
+ err = EPERM;
+ break;
+ case VMCI_ERROR_NO_RESOURCES:
+ err = ENOBUFS;
+ break;
+ case VMCI_ERROR_INVALID_RESOURCE:
+ err = EHOSTUNREACH;
+ break;
+ case VMCI_ERROR_MODULE_NOT_LOADED:
+ err = ESYSNOTREADY;
+ break;
+ case VMCI_ERROR_INVALID_ARGS:
+ default:
+ err = EINVAL;
+ }
+
+ return sockerr2err(err);
+}
+
+#endif
diff --git a/net/vmw_vsock/vsock_packet.h b/net/vmw_vsock/vsock_packet.h
new file mode 100644
index 0000000..0e6782f
--- /dev/null
+++ b/net/vmw_vsock/vsock_packet.h
@@ -0,0 +1,92 @@
+/*
+ * VMware vSockets Driver
+ *
+ * Copyright (C) 2007-2012 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _VSOCK_PACKET_H_
+#define _VSOCK_PACKET_H_
+
+#include "vmci_sockets_packet.h"
+
+static inline void
+vsock_packet_init(struct vsock_packet *pkt,
+ struct sockaddr_vm *src,
+ struct sockaddr_vm *dst,
+ u8 type,
+ u64 size,
+ u64 mode,
+ struct vsock_waiting_info *wait,
+ vsock_proto_version proto,
+ struct vmci_handle handle)
+{
+ /* We register the stream control handler as an any cid handle so we
+ * must always send from a source address of VMADDR_CID_ANY
+ */
+ pkt->dg.src = vmci_make_handle(VMADDR_CID_ANY, VSOCK_PACKET_RID);
+ pkt->dg.dst = vmci_make_handle(dst->svm_cid, VSOCK_PACKET_RID);
+ pkt->dg.payload_size = sizeof(*pkt) - sizeof(pkt->dg);
+ pkt->version = VSOCK_PACKET_VERSION;
+ pkt->type = type;
+ pkt->src_port = src->svm_port;
+ pkt->dst_port = dst->svm_port;
+ memset(&pkt->proto, 0, sizeof(pkt->proto));
+ memset(&pkt->_reserved2, 0, sizeof(pkt->_reserved2));
+
+ switch (pkt->type) {
+ case VSOCK_PACKET_TYPE_INVALID:
+ pkt->u.size = 0;
+ break;
+
+ case VSOCK_PACKET_TYPE_REQUEST:
+ case VSOCK_PACKET_TYPE_NEGOTIATE:
+ pkt->u.size = size;
+ break;
+
+ case VSOCK_PACKET_TYPE_OFFER:
+ case VSOCK_PACKET_TYPE_ATTACH:
+ pkt->u.handle = handle;
+ break;
+
+ case VSOCK_PACKET_TYPE_WROTE:
+ case VSOCK_PACKET_TYPE_READ:
+ case VSOCK_PACKET_TYPE_RST:
+ pkt->u.size = 0;
+ break;
+
+ case VSOCK_PACKET_TYPE_SHUTDOWN:
+ pkt->u.mode = mode;
+ break;
+
+ case VSOCK_PACKET_TYPE_WAITING_READ:
+ case VSOCK_PACKET_TYPE_WAITING_WRITE:
+ memcpy(&pkt->u.wait, wait, sizeof(pkt->u.wait));
+ break;
+
+ case VSOCK_PACKET_TYPE_REQUEST2:
+ case VSOCK_PACKET_TYPE_NEGOTIATE2:
+ pkt->u.size = size;
+ pkt->proto = proto;
+ break;
+ }
+}
+
+static inline void
+vsock_packet_get_addresses(struct vsock_packet *pkt,
+ struct sockaddr_vm *local,
+ struct sockaddr_vm *remote)
+{
+ vsock_addr_init(local, pkt->dg.dst.context, pkt->dst_port);
+ vsock_addr_init(remote, pkt->dg.src.context, pkt->src_port);
+}
+
+#endif
diff --git a/net/vmw_vsock/vsock_version.h b/net/vmw_vsock/vsock_version.h
new file mode 100644
index 0000000..4df7f5e
--- /dev/null
+++ b/net/vmw_vsock/vsock_version.h
@@ -0,0 +1,22 @@
+/*
+ * VMware vSockets Driver
+ *
+ * Copyright (C) 2011-2012 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation version 2 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#ifndef _VSOCK_VERSION_H_
+#define _VSOCK_VERSION_H_
+
+#define VSOCK_DRIVER_VERSION_PARTS { 1, 0, 0, 0 }
+#define VSOCK_DRIVER_VERSION_STRING "1.0.0.0-k"
+
+#endif /* _VSOCK_VERSION_H_ */
^ permalink raw reply related
* [PATCH] ipv6: Netlink notify forwarding change
From: Saurabh Mohan @ 2013-01-09 0:11 UTC (permalink / raw)
To: netdev
If the interface is up and the forwarding attribute
(net.ipv6.conf.eth1.forwarding) is changed then a netlink message is not
generated.
Signed-off-by: Saurabh Mohan <saurabh.mohan@vyatta.com>
---
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 0f9f15e..a959606 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -130,6 +130,8 @@ static void ipv6_regen_rndid(unsigned long data);
static int ipv6_generate_eui64(u8 *eui, struct net_device *dev);
static int ipv6_count_addresses(struct inet6_dev *idev);
+static int addrconf_notify(struct notifier_block *this, unsigned long event,
+ void *data);
/*
* Configured unicast address hash table
@@ -467,6 +469,9 @@ static void dev_forward_change(struct inet6_dev *idev)
if (!idev)
return;
+
+ addrconf_notify(NULL, NETDEV_CHANGE, idev->dev);
+
dev = idev->dev;
if (idev->cnf.forwarding)
dev_disable_lro(dev);
@@ -2615,9 +2620,11 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
}
if (idev) {
- if (idev->if_flags & IF_READY)
+ if (idev->if_flags & IF_READY) {
/* device is already configured. */
+ inet6_ifinfo_notify(RTM_NEWLINK, idev);
break;
+ }
idev->if_flags |= IF_READY;
}
^ permalink raw reply related
* Re: [PATCH 0/6] VSOCK for Linux upstreaming
From: Greg KH @ 2013-01-09 0:21 UTC (permalink / raw)
To: George Zhang; +Cc: pv-drivers, netdev, davem, linux-kernel, virtualization
In-Reply-To: <20130108235633.3719.6085.stgit@promb-2n-dhcp175.eng.vmware.com>
On Tue, Jan 08, 2013 at 03:59:08PM -0800, George Zhang wrote:
>
> * * *
>
> This series of VSOCK linux upstreaming patches include latest udpate from
> VMware to address Greg's and all other's code review comments.
Dave, you acked these patches a while ago, and now that I've taken the
VMCI patches that these depend on through my char-misc tree, can I take
these as well?
thanks,
greg k-h
^ permalink raw reply
* Re: xen-netback notify DomU to send ARP.
From: Jason Luan @ 2013-01-09 1:07 UTC (permalink / raw)
To: Ian Campbell; +Cc: netdev, xen-devel, konrad.wilk
In-Reply-To: <1357660834.12649.103.camel@dagon.hellion.org.uk>
于 2013年01月09日 00:00, Ian Campbell 写道:
> On Tue, 2013-01-08 at 15:40 +0000, jianhai luan wrote:
>> On 2013-1-8 21:42, Ian Campbell wrote:
>>> On Tue, 2013-01-08 at 13:13 +0000, Jan Beulich wrote:
>>>>>>> On 08.01.13 at 12:57, jianhai luan <jianhai.luan@oracle.com>
>>>>>>> wrote:
>>>>> When Xen Dom0's network circumstance changed, DomU
>>>>> should be notified in some special condition. For
>>>>> example the below circumstance:
>>>>> ping from Guest A to DomU:
>>>>> Guest A --> eth0 - bond0 - xenbr0 --VIF(DOMU)
>>>>> eth1 /
>>>>> when eth0 inactive, and eth1 active.
>>> How is eth0 failing? Are you unplugging it, un-enslaving it or
>>> taking
>>> some other sort of administrative action?
>> In my emulation environment, i unplug it or ifdown the interface,
> I expect these would behave rather different, since the affect of ifdown
> looks rather different to an unplug from the PoV of the switch.
>
> Is the ifdown case something which you are trying to solve or just what
> appeared to be a convenient test case? I'd be less inclined to worry
> about explict admin actions such as that.
>
> Unplugging the cable should cause:
>
I do above listed thing to let switch active slave only.
I think that we should put attention on the thing which bond switch
active slave interface in active-backup mode. In network circumstance,
many thing will cause the switch, what do Vif when the event happen?
>>> Doesn't this state change cause the switch to which eth0 and eth1
>>> are
>>> attached to forget the MAC tables associated with the eth0 port,
>>> meaning
>>> that subsequent traffic will be flooded until it learns that eth1 is
>>> the
>>> new port?
> Ian
>
>
>
> _______________________________________________
> Xen-devel mailing list
Thanks,
Jason
> Xen-devel@lists.xen.org
> http://lists.xen.org/xen-devel
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel
^ permalink raw reply
* Re: [PATCH 0/6] VSOCK for Linux upstreaming
From: David Miller @ 2013-01-09 1:30 UTC (permalink / raw)
To: gregkh; +Cc: pv-drivers, netdev, linux-kernel, georgezhang, virtualization
In-Reply-To: <20130109002110.GB5296@kroah.com>
From: Greg KH <gregkh@linuxfoundation.org>
Date: Tue, 8 Jan 2013 16:21:10 -0800
> On Tue, Jan 08, 2013 at 03:59:08PM -0800, George Zhang wrote:
>>
>> * * *
>>
>> This series of VSOCK linux upstreaming patches include latest udpate from
>> VMware to address Greg's and all other's code review comments.
>
> Dave, you acked these patches a while ago,
Really? I'd like to see where I did that.
Instead, what I remember doing was deferring to the feedback these
folks received, stating that ideas that the virtio people had
mentioned should be considered instead.
http://marc.info/?l=linux-netdev&m=135301515818462&w=2
So definitely NACK this code and any infrastructure you've
merged which essentialy depends upon it.
^ permalink raw reply
* Re: [Pv-drivers] [PATCH 0/6] VSOCK for Linux upstreaming
From: Dmitry Torokhov @ 2013-01-09 1:41 UTC (permalink / raw)
To: pv-drivers; +Cc: gregkh, virtualization, David Miller, linux-kernel, netdev
In-Reply-To: <20130108.173056.1029788106028104571.davem@davemloft.net>
On Tuesday, January 08, 2013 05:30:56 PM David Miller wrote:
> From: Greg KH <gregkh@linuxfoundation.org>
> Date: Tue, 8 Jan 2013 16:21:10 -0800
>
> > On Tue, Jan 08, 2013 at 03:59:08PM -0800, George Zhang wrote:
> >> * * *
> >>
> >> This series of VSOCK linux upstreaming patches include latest udpate from
> >> VMware to address Greg's and all other's code review comments.
> >
> > Dave, you acked these patches a while ago,
>
> Really? I'd like to see where I did that.
>
> Instead, what I remember doing was deferring to the feedback these
> folks received, stating that ideas that the virtio people had
> mentioned should be considered instead.
>
> http://marc.info/?l=linux-netdev&m=135301515818462&w=2
I believe Andy replied to Anthony's AF_VMCHANNEL post and the differences
between the proposed solutions.
>
> So definitely NACK this code and any infrastructure you've
> merged which essentialy depends upon it.
No, there is no infrastructure that depends on VSOCK, as VSOCK is built
on top of VMCI, not the other way around.
Thanks,
Dmitry
^ permalink raw reply
* Re: [Pv-drivers] [PATCH 0/6] VSOCK for Linux upstreaming
From: David Miller @ 2013-01-09 1:46 UTC (permalink / raw)
To: dtor; +Cc: pv-drivers, gregkh, virtualization, linux-kernel, netdev
In-Reply-To: <1683801.VNKd61ZM1Q@dtor-d630.eng.vmware.com>
From: Dmitry Torokhov <dtor@vmware.com>
Date: Tue, 08 Jan 2013 17:41:44 -0800
> On Tuesday, January 08, 2013 05:30:56 PM David Miller wrote:
>> From: Greg KH <gregkh@linuxfoundation.org>
>> Date: Tue, 8 Jan 2013 16:21:10 -0800
>>
>> > On Tue, Jan 08, 2013 at 03:59:08PM -0800, George Zhang wrote:
>> >> * * *
>> >>
>> >> This series of VSOCK linux upstreaming patches include latest udpate from
>> >> VMware to address Greg's and all other's code review comments.
>> >
>> > Dave, you acked these patches a while ago,
>>
>> Really? I'd like to see where I did that.
>>
>> Instead, what I remember doing was deferring to the feedback these
>> folks received, stating that ideas that the virtio people had
>> mentioned should be considered instead.
>>
>> http://marc.info/?l=linux-netdev&m=135301515818462&w=2
>
> I believe Andy replied to Anthony's AF_VMCHANNEL post and the differences
> between the proposed solutions.
I'd much rather see a hypervisor neutral solution than a hypervisor
specific one which this certainly is.
^ permalink raw reply
* Re: [RFC/PATCH net-next 0/1] Delete obsolete 8390 EISA drivers
From: David Miller @ 2013-01-09 1:50 UTC (permalink / raw)
To: paul.gortmaker; +Cc: netdev
In-Reply-To: <1357582618-17183-1-git-send-email-paul.gortmaker@windriver.com>
From: Paul Gortmaker <paul.gortmaker@windriver.com>
Date: Mon, 7 Jan 2013 13:16:57 -0500
> git://git.kernel.org/pub/scm/linux/kernel/git/paulg/linux.git delete-8390-EISA
No objections, pulled, thanks Paul.
^ permalink raw reply
* Re: [PATCH net-next] net: introduce skb_transport_header_was_set()
From: David Miller @ 2013-01-09 1:52 UTC (permalink / raw)
To: eric.dumazet; +Cc: jhs, netdev
In-Reply-To: <1357586901.6919.3551.camel@edumazet-glaptop>
From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Mon, 07 Jan 2013 11:28:21 -0800
> [PATCH net-next] net: introduce skb_transport_header_was_set()
>
> We have skb_mac_header_was_set() helper to tell if mac_header
> was set on a skb. We would like the same for transport_header.
>
> __netif_receive_skb() doesn't reset the transport header if already
> set by GRO layer.
>
> Note that network stacks usually reset the transport header anyway,
> after pulling the network header, so this change only allows
> a followup patch to have more precise qdisc pkt_len computation
> for GSO packets at ingress side.
>
> Signed-off-by: Eric Dumazet <edumazet@google.com>
Applied.
^ permalink raw reply
* Re: [PATCH V3 1/2] virtio-net: fix the set affinity bug when CPU IDs are not consecutive
From: Wanlong Gao @ 2013-01-09 1:52 UTC (permalink / raw)
To: Jason Wang
Cc: Michael S. Tsirkin, netdev, linux-kernel, virtualization,
Eric Dumazet
In-Reply-To: <50EBF44C.9040401@redhat.com>
On 01/08/2013 06:26 PM, Jason Wang wrote:
> On 01/08/2013 06:07 PM, Wanlong Gao wrote:
>> As Michael mentioned, set affinity and select queue will not work very
>> well when CPU IDs are not consecutive, this can happen with hot unplug.
>> Fix this bug by traversal the online CPUs, and create a per cpu variable
>> to find the mapping from CPU to the preferable virtual-queue.
>>
>> Cc: Rusty Russell <rusty@rustcorp.com.au>
>> Cc: "Michael S. Tsirkin" <mst@redhat.com>
>> Cc: Jason Wang <jasowang@redhat.com>
>> Cc: Eric Dumazet <erdnetdev@gmail.com>
>> Cc: virtualization@lists.linux-foundation.org
>> Cc: netdev@vger.kernel.org
>> Signed-off-by: Wanlong Gao <gaowanlong@cn.fujitsu.com>
>> ---
>> drivers/net/virtio_net.c | 39 +++++++++++++++++++++++++++++----------
>> 1 file changed, 29 insertions(+), 10 deletions(-)
>>
>> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
>> index a6fcf15..a77f86c 100644
>> --- a/drivers/net/virtio_net.c
>> +++ b/drivers/net/virtio_net.c
>> @@ -41,6 +41,8 @@ module_param(gso, bool, 0444);
>> #define VIRTNET_SEND_COMMAND_SG_MAX 2
>> #define VIRTNET_DRIVER_VERSION "1.0.0"
>>
>> +DEFINE_PER_CPU(int, vq_index) = -1;
>> +
>
> I think this should not be a global one, consider we may have more than
> one virtio-net cards with different max queues.
Yes, would you move this into virtio_info?
>> struct virtnet_stats {
>> struct u64_stats_sync tx_syncp;
>> struct u64_stats_sync rx_syncp;
>> @@ -1016,6 +1018,7 @@ static int virtnet_vlan_rx_kill_vid(struct net_device *dev, u16 vid)
>> static void virtnet_set_affinity(struct virtnet_info *vi, bool set)
>> {
>> int i;
>> + int cpu;
>>
>> /* In multiqueue mode, when the number of cpu is equal to the number of
>> * queue pairs, we let the queue pairs to be private to one cpu by
>> @@ -1029,16 +1032,29 @@ static void virtnet_set_affinity(struct virtnet_info *vi, bool set)
>> return;
>> }
>>
>> - for (i = 0; i < vi->max_queue_pairs; i++) {
>> - int cpu = set ? i : -1;
>> - virtqueue_set_affinity(vi->rq[i].vq, cpu);
>> - virtqueue_set_affinity(vi->sq[i].vq, cpu);
>> - }
>> + if (set) {
>> + i = 0;
>> + for_each_online_cpu(cpu) {
>> + virtqueue_set_affinity(vi->rq[i].vq, cpu);
>> + virtqueue_set_affinity(vi->sq[i].vq, cpu);
>> + per_cpu(vq_index, cpu) = i;
>> + i++;
>> + if (i >= vi->max_queue_pairs)
>> + break;
>
> Can this happen? we check only set when the number are equal.
will remove.
>> + }
>>
>> - if (set)
>> vi->affinity_hint_set = true;
>> - else
>> + } else {
>> + for(i = 0; i < vi->max_queue_pairs; i++) {
>> + virtqueue_set_affinity(vi->rq[i].vq, -1);
>> + virtqueue_set_affinity(vi->sq[i].vq, -1);
>> + }
>> +
>> + for_each_online_cpu(cpu)
>> + per_cpu(vq_index, cpu) = -1;
>> +
>
> This looks suboptimal since it may leads only txq zero is used.
So, which value is best for txq when we don't set affinity?
just remain to smp_processor_id()?
Thanks,
Wanlong Gao
>> vi->affinity_hint_set = false;
>> + }
>> }
>>
>> static void virtnet_get_ringparam(struct net_device *dev,
>> @@ -1127,12 +1143,15 @@ static int virtnet_change_mtu(struct net_device *dev, int new_mtu)
>>
>> /* To avoid contending a lock hold by a vcpu who would exit to host, select the
>> * txq based on the processor id.
>> - * TODO: handle cpu hotplug.
>> */
>> static u16 virtnet_select_queue(struct net_device *dev, struct sk_buff *skb)
>> {
>> - int txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) :
>> - smp_processor_id();
>> + int txq = 0;
>> +
>> + if (skb_rx_queue_recorded(skb))
>> + txq = skb_get_rx_queue(skb);
>> + else if ((txq = per_cpu(vq_index, smp_processor_id())) == -1)
>> + txq = 0;
>>
>> while (unlikely(txq >= dev->real_num_tx_queues))
>> txq -= dev->real_num_tx_queues;
>
>
^ permalink raw reply
* Re: [PATCH v3] net: fec: Remove 'inline' declarations
From: David Miller @ 2013-01-09 1:54 UTC (permalink / raw)
To: festevam; +Cc: shawn.guo, netdev, joe, fabio.estevam
In-Reply-To: <1357616576-25307-1-git-send-email-festevam@gmail.com>
From: Fabio Estevam <festevam@gmail.com>
Date: Tue, 8 Jan 2013 01:42:56 -0200
> From: Fabio Estevam <fabio.estevam@freescale.com>
>
> Fix the following warning when building with W=1 option:
>
> drivers/net/ethernet/freescale/fec.c:810:1: warning: '__inline__' is not at beginning of declaration [-Wold-style-declaration]
>
> The inline declaration is pointless in this function, so just remove it.
>
> While at it, also remove the other 'inline' declarations.
>
> Signed-off-by: Fabio Estevam <fabio.estevam@freescale.com>
Applied to net-next.
^ permalink raw reply
* Re: [PATCH V3 1/2] virtio-net: fix the set affinity bug when CPU IDs are not consecutive
From: Wanlong Gao @ 2013-01-09 1:54 UTC (permalink / raw)
To: Rusty Russell
Cc: Michael S. Tsirkin, netdev, linux-kernel, virtualization,
Eric Dumazet
In-Reply-To: <87k3rn2qwb.fsf@rustcorp.com.au>
On 01/09/2013 07:31 AM, Rusty Russell wrote:
> Wanlong Gao <gaowanlong@cn.fujitsu.com> writes:
>> */
>> static u16 virtnet_select_queue(struct net_device *dev, struct sk_buff *skb)
>> {
>> - int txq = skb_rx_queue_recorded(skb) ? skb_get_rx_queue(skb) :
>> - smp_processor_id();
>> + int txq = 0;
>> +
>> + if (skb_rx_queue_recorded(skb))
>> + txq = skb_get_rx_queue(skb);
>> + else if ((txq = per_cpu(vq_index, smp_processor_id())) == -1)
>> + txq = 0;
>
> You should use __get_cpu_var() instead of smp_processor_id() here, ie:
>
> else if ((txq = __get_cpu_var(vq_index)) == -1)
>
> And AFAICT, no reason to initialize txq to 0 to start with.
>
> So:
>
> int txq;
>
> if (skb_rx_queue_recorded(skb))
> txq = skb_get_rx_queue(skb);
> else {
> txq = __get_cpu_var(vq_index);
> if (txq == -1)
> txq = 0;
> }
Got it, thank you.
>
> Now, just to confirm, I assume this can happen even if we use vq_index,
> right, because of races with virtnet_set_channels?
I still can't understand this race, could you explain more? thank you.
Regards,
Wanlong Gao
>
> while (unlikely(txq >= dev->real_num_tx_queues))
> txq -= dev->real_num_tx_queues;
>
>
> Thanks,
> Rusty.
>
^ permalink raw reply
* Re: [PATCH V5] bgmac: driver for GBit MAC core on BCMA bus
From: David Miller @ 2013-01-09 1:55 UTC (permalink / raw)
To: zajec5; +Cc: netdev, romieu, joe
In-Reply-To: <1357626888-2375-1-git-send-email-zajec5@gmail.com>
From: Rafał Miłecki <zajec5@gmail.com>
Date: Tue, 8 Jan 2013 07:34:48 +0100
> BCMA is a Broadcom specific bus with devices AKA cores. All recent BCMA
> based SoCs have gigabit ethernet provided by the GBit MAC core. This
> patch adds driver for such a cores registering itself as a netdev. It
> has been tested on a BCM4706 and BCM4718 chipsets.
>
> In the kernel tree there is already b44 driver which has some common
> things with bgmac, however there are many differences that has led to
> the decision or writing a new driver:
> 1) GBit MAC cores appear on BCMA bus (not SSB as in case of b44)
> 2) There is 64bit DMA engine which differs from 32bit one
> 3) There is no CAM (Content Addressable Memory) in GBit MAC
> 4) We have 4 TX queues on GBit MAC devices (instead of 1)
> 5) Many registers have different addresses/values
> 6) RX header flags are also different
>
> The driver in it's state is functional how, however there is of course
> place for improvements:
> 1) Supporting more net_device_ops
> 2) SUpporting more ethtool_ops
> 3) Unaligned addressing in DMA
> 4) Writing separated PHY driver
>
> Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
This patch doesn't apply to the net-next tree, please re-spin.
^ permalink raw reply
* Re: [PATCH net-next v5 0/4] netpoll: add IPv6 support
From: David Miller @ 2013-01-09 1:56 UTC (permalink / raw)
To: amwang; +Cc: netdev
In-Reply-To: <1357627962-28683-1-git-send-email-amwang@redhat.com>
From: Cong Wang <amwang@redhat.com>
Date: Tue, 8 Jan 2013 14:52:38 +0800
> v5: move some ipv6 checksum functions into net/ipv6/ip6_checksum.c
>
> v4: remove ndisc_parse_options(), ignore ICMP options there
> make udp6_csum_init() inline so that we don't rely on IPV6=y
> fix a conflict with Jiri's patchset
>
> v3: fix CONFIG_IPV6=m case
>
> v2: use bool for ipv6 flag
> fix !CONFIG_IPV6 case
>
> This patchset implements netpoll over IPv6.
Series applied, thanks.
^ permalink raw reply
* Re: [Patch] net: prevent setting ttl=0 via IP_TTL
From: David Miller @ 2013-01-09 1:57 UTC (permalink / raw)
To: xiyou.wangcong; +Cc: netdev, padalia.nitin, eric.dumazet
In-Reply-To: <1357629420-29725-1-git-send-email-xiyou.wangcong@gmail.com>
From: Cong Wang <xiyou.wangcong@gmail.com>
Date: Tue, 8 Jan 2013 15:17:00 +0800
> From: Cong Wang <xiyou.wangcong@gmail.com>
>
> A regression is introduced by the following commit:
>
> commit 4d52cfbef6266092d535237ba5a4b981458ab171
> Author: Eric Dumazet <eric.dumazet@gmail.com>
> Date: Tue Jun 2 00:42:16 2009 -0700
>
> net: ipv4/ip_sockglue.c cleanups
>
> Pure cleanups
>
> but it is not a pure cleanup...
>
> - if (val != -1 && (val < 1 || val>255))
> + if (val != -1 && (val < 0 || val > 255))
>
> Since there is no reason provided to allow ttl=0, change it back.
>
> Reported-by: nitin padalia <padalia.nitin@gmail.com>
> Cc: nitin padalia <padalia.nitin@gmail.com>
> Cc: Eric Dumazet <eric.dumazet@gmail.com>
> Cc: David S. Miller <davem@davemloft.net>
> Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Applied and queued up for -stable, thanks.
^ permalink raw reply
* Re: [PATCH 1/1 net-next] net: fec: enable pause frame to improve rx prefomance for 1G network
From: David Miller @ 2013-01-09 1:58 UTC (permalink / raw)
To: Frank.Li; +Cc: lznuaa, shawn.guo, B38611, linux-arm-kernel, netdev, s.hauer
In-Reply-To: <1357634609-4112-1-git-send-email-Frank.Li@freescale.com>
As others have mentioned, this is definitely something which must be
automatically detected via PHY autonegotiation results or the user
forcing the setting via ethtool. Not like this.
^ permalink raw reply
* Re: [patch net-next 0/2] net: init perm_addr properly and on one place
From: David Miller @ 2013-01-09 2:01 UTC (permalink / raw)
To: jiri; +Cc: netdev, edumazet, bhutchings, shemminger, ebiederm, amwang,
sassmann
In-Reply-To: <1357645106-1976-1-git-send-email-jiri@resnulli.us>
From: Jiri Pirko <jiri@resnulli.us>
Date: Tue, 8 Jan 2013 12:38:24 +0100
> So far, it has been driver's responsibility to initialize ->perm_addr. Many
> of them does not do that though. So benefit from ->addr_assign_type existence
> and in case the type is NET_ADDR_PERM, set the ->perm_addr during dev register
> process. That allows to remove most of the driver's initializations (that what
> happen before register_netdevice() call).
>
> Jiri Pirko (2):
> net: init perm_addr in register_netdevice()
> remove init of dev->perm_addr in drivers
Nice cleanup, all applied, thanks!
^ permalink raw reply
* [PATCH V2 0/4] DSA: Fix checkpatch.pl output for DSA drivers
From: Barry Grussling @ 2013-01-09 2:05 UTC (permalink / raw)
To: netdev; +Cc: Barry Grussling
This set of patches performs routine maintenance on the DSA drivers
by removing all checkpatch.pl errors.
These patches do the following things:
* Switch to network-style comments
* Convert msleep calls to timeout/usleep_range calls
* Convert printk calls to netdev_info calls
* Fix whitespace issues
Changes from V1 of the patch include:
(Joe Perches Review)
* Change comment style to one-line for comments
that can be reduced to one-line
* Fix spelling of "Priority"
* Remove device name from netdev_info
* Coalesce netdev_info lines to one format line
(Ben Hutchings Review)
* Replace repeated usleep_range calls with
timeouts/usleep_range calls.
Thanks,
Barry
Barry Grussling (4):
DSA: Convert DSA comments to network-style comments
DSA: Convert repeated msleep calls to timeouts
DSA: Convert printk calls to netdev_info calls
DSA: Convert spaces to tabs where appropriate
drivers/net/dsa/mv88e6060.c | 54 ++++++--------
drivers/net/dsa/mv88e6123_61_65.c | 125 +++++++++++---------------------
drivers/net/dsa/mv88e6131.c | 114 ++++++++++--------------------
drivers/net/dsa/mv88e6xxx.c | 141 +++++++++++++++----------------------
drivers/net/dsa/mv88e6xxx.h | 11 ++-
5 files changed, 162 insertions(+), 283 deletions(-)
--
1.7.9.5
^ permalink raw reply
* [PATCH V2 1/4] DSA: Convert DSA comments to network-style comments
From: Barry Grussling @ 2013-01-09 2:05 UTC (permalink / raw)
To: netdev; +Cc: Barry Grussling
In-Reply-To: <1357697156-5767-1-git-send-email-barry@grussling.com>
From: Barry Grussling <barry@grussling.com>
Convert DSA driver comments to network-style comments as reported by
checkpatch.pl. Fix spelling error.
Signed-off-by: Barry Grussling <barry@grussling.com>
---
drivers/net/dsa/mv88e6060.c | 31 +++-------
drivers/net/dsa/mv88e6123_61_65.c | 113 +++++++++++--------------------------
drivers/net/dsa/mv88e6131.c | 102 ++++++++++-----------------------
drivers/net/dsa/mv88e6xxx.c | 70 ++++++-----------------
drivers/net/dsa/mv88e6xxx.h | 9 +--
5 files changed, 93 insertions(+), 232 deletions(-)
diff --git a/drivers/net/dsa/mv88e6060.c b/drivers/net/dsa/mv88e6060.c
index 325391d..637373c 100644
--- a/drivers/net/dsa/mv88e6060.c
+++ b/drivers/net/dsa/mv88e6060.c
@@ -67,27 +67,19 @@ static int mv88e6060_switch_reset(struct dsa_switch *ds)
int i;
int ret;
- /*
- * Set all ports to the disabled state.
- */
+ /* Set all ports to the disabled state. */
for (i = 0; i < 6; i++) {
ret = REG_READ(REG_PORT(i), 0x04);
REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc);
}
- /*
- * Wait for transmit queues to drain.
- */
+ /* Wait for transmit queues to drain. */
msleep(2);
- /*
- * Reset the switch.
- */
+ /* Reset the switch. */
REG_WRITE(REG_GLOBAL, 0x0a, 0xa130);
- /*
- * Wait up to one second for reset to complete.
- */
+ /* Wait up to one second for reset to complete. */
for (i = 0; i < 1000; i++) {
ret = REG_READ(REG_GLOBAL, 0x00);
if ((ret & 0x8000) == 0x0000)
@@ -103,15 +95,13 @@ static int mv88e6060_switch_reset(struct dsa_switch *ds)
static int mv88e6060_setup_global(struct dsa_switch *ds)
{
- /*
- * Disable discarding of frames with excessive collisions,
+ /* Disable discarding of frames with excessive collisions,
* set the maximum frame size to 1536 bytes, and mask all
* interrupt sources.
*/
REG_WRITE(REG_GLOBAL, 0x04, 0x0800);
- /*
- * Enable automatic address learning, set the address
+ /* Enable automatic address learning, set the address
* database size to 1024 entries, and set the default aging
* time to 5 minutes.
*/
@@ -124,16 +114,14 @@ static int mv88e6060_setup_port(struct dsa_switch *ds, int p)
{
int addr = REG_PORT(p);
- /*
- * Do not force flow control, disable Ingress and Egress
+ /* Do not force flow control, disable Ingress and Egress
* Header tagging, disable VLAN tunneling, and set the port
* state to Forwarding. Additionally, if this is the CPU
* port, enable Ingress and Egress Trailer tagging mode.
*/
REG_WRITE(addr, 0x04, dsa_is_cpu_port(ds, p) ? 0x4103 : 0x0003);
- /*
- * Port based VLAN map: give each port its own address
+ /* Port based VLAN map: give each port its own address
* database, allow the CPU port to talk to each of the 'real'
* ports, and allow each of the 'real' ports to only talk to
* the CPU port.
@@ -144,8 +132,7 @@ static int mv88e6060_setup_port(struct dsa_switch *ds, int p)
ds->phys_port_mask :
(1 << ds->dst->cpu_port)));
- /*
- * Port Association Vector: when learning source addresses
+ /* Port Association Vector: when learning source addresses
* of packets, add the address to the address database using
* a port bitmap that has only the bit for this port set and
* the other bits clear.
diff --git a/drivers/net/dsa/mv88e6123_61_65.c b/drivers/net/dsa/mv88e6123_61_65.c
index c17c75b..a644fc9 100644
--- a/drivers/net/dsa/mv88e6123_61_65.c
+++ b/drivers/net/dsa/mv88e6123_61_65.c
@@ -51,27 +51,19 @@ static int mv88e6123_61_65_switch_reset(struct dsa_switch *ds)
int i;
int ret;
- /*
- * Set all ports to the disabled state.
- */
+ /* Set all ports to the disabled state. */
for (i = 0; i < 8; i++) {
ret = REG_READ(REG_PORT(i), 0x04);
REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc);
}
- /*
- * Wait for transmit queues to drain.
- */
+ /* Wait for transmit queues to drain. */
msleep(2);
- /*
- * Reset the switch.
- */
+ /* Reset the switch. */
REG_WRITE(REG_GLOBAL, 0x04, 0xc400);
- /*
- * Wait up to one second for reset to complete.
- */
+ /* Wait up to one second for reset to complete. */
for (i = 0; i < 1000; i++) {
ret = REG_READ(REG_GLOBAL, 0x00);
if ((ret & 0xc800) == 0xc800)
@@ -90,54 +82,45 @@ static int mv88e6123_61_65_setup_global(struct dsa_switch *ds)
int ret;
int i;
- /*
- * Disable the PHY polling unit (since there won't be any
+ /* Disable the PHY polling unit (since there won't be any
* external PHYs to poll), don't discard packets with
* excessive collisions, and mask all interrupt sources.
*/
REG_WRITE(REG_GLOBAL, 0x04, 0x0000);
- /*
- * Set the default address aging time to 5 minutes, and
+ /* Set the default address aging time to 5 minutes, and
* enable address learn messages to be sent to all message
* ports.
*/
REG_WRITE(REG_GLOBAL, 0x0a, 0x0148);
- /*
- * Configure the priority mapping registers.
- */
+ /* Configure the priority mapping registers. */
ret = mv88e6xxx_config_prio(ds);
if (ret < 0)
return ret;
- /*
- * Configure the upstream port, and configure the upstream
+ /* Configure the upstream port, and configure the upstream
* port as the port to which ingress and egress monitor frames
* are to be sent.
*/
REG_WRITE(REG_GLOBAL, 0x1a, (dsa_upstream_port(ds) * 0x1110));
- /*
- * Disable remote management for now, and set the switch's
+ /* Disable remote management for now, and set the switch's
* DSA device number.
*/
REG_WRITE(REG_GLOBAL, 0x1c, ds->index & 0x1f);
- /*
- * Send all frames with destination addresses matching
+ /* Send all frames with destination addresses matching
* 01:80:c2:00:00:2x to the CPU port.
*/
REG_WRITE(REG_GLOBAL2, 0x02, 0xffff);
- /*
- * Send all frames with destination addresses matching
+ /* Send all frames with destination addresses matching
* 01:80:c2:00:00:0x to the CPU port.
*/
REG_WRITE(REG_GLOBAL2, 0x03, 0xffff);
- /*
- * Disable the loopback filter, disable flow control
+ /* Disable the loopback filter, disable flow control
* messages, disable flood broadcast override, disable
* removing of provider tags, disable ATU age violation
* interrupts, disable tag flow control, force flow
@@ -146,9 +129,7 @@ static int mv88e6123_61_65_setup_global(struct dsa_switch *ds)
*/
REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff);
- /*
- * Program the DSA routing table.
- */
+ /* Program the DSA routing table. */
for (i = 0; i < 32; i++) {
int nexthop;
@@ -159,33 +140,24 @@ static int mv88e6123_61_65_setup_global(struct dsa_switch *ds)
REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | nexthop);
}
- /*
- * Clear all trunk masks.
- */
+ /* Clear all trunk masks. */
for (i = 0; i < 8; i++)
REG_WRITE(REG_GLOBAL2, 0x07, 0x8000 | (i << 12) | 0xff);
- /*
- * Clear all trunk mappings.
- */
+ /* Clear all trunk mappings. */
for (i = 0; i < 16; i++)
REG_WRITE(REG_GLOBAL2, 0x08, 0x8000 | (i << 11));
- /*
- * Disable ingress rate limiting by resetting all ingress
+ /* Disable ingress rate limiting by resetting all ingress
* rate limit registers to their initial state.
*/
for (i = 0; i < 6; i++)
REG_WRITE(REG_GLOBAL2, 0x09, 0x9000 | (i << 8));
- /*
- * Initialise cross-chip port VLAN table to reset defaults.
- */
+ /* Initialise cross-chip port VLAN table to reset defaults. */
REG_WRITE(REG_GLOBAL2, 0x0b, 0x9000);
- /*
- * Clear the priority override table.
- */
+ /* Clear the priority override table. */
for (i = 0; i < 16; i++)
REG_WRITE(REG_GLOBAL2, 0x0f, 0x8000 | (i << 8));
@@ -199,8 +171,7 @@ static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p)
int addr = REG_PORT(p);
u16 val;
- /*
- * MAC Forcing register: don't force link, speed, duplex
+ /* MAC Forcing register: don't force link, speed, duplex
* or flow control state to any particular values on physical
* ports, but force the CPU port and all DSA ports to 1000 Mb/s
* full duplex.
@@ -210,15 +181,13 @@ static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p)
else
REG_WRITE(addr, 0x01, 0x0003);
- /*
- * Do not limit the period of time that this port can be
+ /* Do not limit the period of time that this port can be
* paused for by the remote end or the period of time that
* this port can pause the remote end.
*/
REG_WRITE(addr, 0x02, 0x0000);
- /*
- * Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
+ /* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
* disable Header mode, enable IGMP/MLD snooping, disable VLAN
* tunneling, determine priority by looking at 802.1p and IP
* priority fields (IP prio has precedence), and set STP state
@@ -245,14 +214,12 @@ static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p)
val |= 0x000c;
REG_WRITE(addr, 0x04, val);
- /*
- * Port Control 1: disable trunking. Also, if this is the
+ /* Port Control 1: disable trunking. Also, if this is the
* CPU port, enable learn messages to be sent to this port.
*/
REG_WRITE(addr, 0x05, dsa_is_cpu_port(ds, p) ? 0x8000 : 0x0000);
- /*
- * Port based VLAN map: give each port its own address
+ /* Port based VLAN map: give each port its own address
* database, allow the CPU port to talk to each of the 'real'
* ports, and allow each of the 'real' ports to only talk to
* the upstream port.
@@ -264,14 +231,12 @@ static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p)
val |= 1 << dsa_upstream_port(ds);
REG_WRITE(addr, 0x06, val);
- /*
- * Default VLAN ID and priority: don't set a default VLAN
+ /* Default VLAN ID and priority: don't set a default VLAN
* ID, and set the default packet priority to zero.
*/
REG_WRITE(addr, 0x07, 0x0000);
- /*
- * Port Control 2: don't force a good FCS, set the maximum
+ /* Port Control 2: don't force a good FCS, set the maximum
* frame size to 10240 bytes, don't let the switch add or
* strip 802.1q tags, don't discard tagged or untagged frames
* on this port, do a destination address lookup on all
@@ -281,48 +246,36 @@ static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p)
*/
REG_WRITE(addr, 0x08, 0x2080);
- /*
- * Egress rate control: disable egress rate control.
- */
+ /* Egress rate control: disable egress rate control. */
REG_WRITE(addr, 0x09, 0x0001);
- /*
- * Egress rate control 2: disable egress rate control.
- */
+ /* Egress rate control 2: disable egress rate control. */
REG_WRITE(addr, 0x0a, 0x0000);
- /*
- * Port Association Vector: when learning source addresses
+ /* Port Association Vector: when learning source addresses
* of packets, add the address to the address database using
* a port bitmap that has only the bit for this port set and
* the other bits clear.
*/
REG_WRITE(addr, 0x0b, 1 << p);
- /*
- * Port ATU control: disable limiting the number of address
+ /* Port ATU control: disable limiting the number of address
* database entries that this port is allowed to use.
*/
REG_WRITE(addr, 0x0c, 0x0000);
- /*
- * Priorit Override: disable DA, SA and VTU priority override.
- */
+ /* Priority Override: disable DA, SA and VTU priority override. */
REG_WRITE(addr, 0x0d, 0x0000);
- /*
- * Port Ethertype: use the Ethertype DSA Ethertype value.
- */
+ /* Port Ethertype: use the Ethertype DSA Ethertype value. */
REG_WRITE(addr, 0x0f, ETH_P_EDSA);
- /*
- * Tag Remap: use an identity 802.1p prio -> switch prio
+ /* Tag Remap: use an identity 802.1p prio -> switch prio
* mapping.
*/
REG_WRITE(addr, 0x18, 0x3210);
- /*
- * Tag Remap 2: use an identity 802.1p prio -> switch prio
+ /* Tag Remap 2: use an identity 802.1p prio -> switch prio
* mapping.
*/
REG_WRITE(addr, 0x19, 0x7654);
diff --git a/drivers/net/dsa/mv88e6131.c b/drivers/net/dsa/mv88e6131.c
index 55888b0..b613818 100644
--- a/drivers/net/dsa/mv88e6131.c
+++ b/drivers/net/dsa/mv88e6131.c
@@ -15,9 +15,7 @@
#include <net/dsa.h>
#include "mv88e6xxx.h"
-/*
- * Switch product IDs
- */
+/* Switch product IDs */
#define ID_6085 0x04a0
#define ID_6095 0x0950
#define ID_6131 0x1060
@@ -45,27 +43,19 @@ static int mv88e6131_switch_reset(struct dsa_switch *ds)
int i;
int ret;
- /*
- * Set all ports to the disabled state.
- */
+ /* Set all ports to the disabled state. */
for (i = 0; i < 11; i++) {
ret = REG_READ(REG_PORT(i), 0x04);
REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc);
}
- /*
- * Wait for transmit queues to drain.
- */
+ /* Wait for transmit queues to drain. */
msleep(2);
- /*
- * Reset the switch.
- */
+ /* Reset the switch. */
REG_WRITE(REG_GLOBAL, 0x04, 0xc400);
- /*
- * Wait up to one second for reset to complete.
- */
+ /* Wait up to one second for reset to complete. */
for (i = 0; i < 1000; i++) {
ret = REG_READ(REG_GLOBAL, 0x00);
if ((ret & 0xc800) == 0xc800)
@@ -84,42 +74,34 @@ static int mv88e6131_setup_global(struct dsa_switch *ds)
int ret;
int i;
- /*
- * Enable the PHY polling unit, don't discard packets with
+ /* Enable the PHY polling unit, don't discard packets with
* excessive collisions, use a weighted fair queueing scheme
* to arbitrate between packet queues, set the maximum frame
* size to 1632, and mask all interrupt sources.
*/
REG_WRITE(REG_GLOBAL, 0x04, 0x4400);
- /*
- * Set the default address aging time to 5 minutes, and
+ /* Set the default address aging time to 5 minutes, and
* enable address learn messages to be sent to all message
* ports.
*/
REG_WRITE(REG_GLOBAL, 0x0a, 0x0148);
- /*
- * Configure the priority mapping registers.
- */
+ /* Configure the priority mapping registers. */
ret = mv88e6xxx_config_prio(ds);
if (ret < 0)
return ret;
- /*
- * Set the VLAN ethertype to 0x8100.
- */
+ /* Set the VLAN ethertype to 0x8100. */
REG_WRITE(REG_GLOBAL, 0x19, 0x8100);
- /*
- * Disable ARP mirroring, and configure the upstream port as
+ /* Disable ARP mirroring, and configure the upstream port as
* the port to which ingress and egress monitor frames are to
* be sent.
*/
REG_WRITE(REG_GLOBAL, 0x1a, (dsa_upstream_port(ds) * 0x1100) | 0x00f0);
- /*
- * Disable cascade port functionality unless this device
+ /* Disable cascade port functionality unless this device
* is used in a cascade configuration, and set the switch's
* DSA device number.
*/
@@ -128,23 +110,19 @@ static int mv88e6131_setup_global(struct dsa_switch *ds)
else
REG_WRITE(REG_GLOBAL, 0x1c, 0xe000 | (ds->index & 0x1f));
- /*
- * Send all frames with destination addresses matching
+ /* Send all frames with destination addresses matching
* 01:80:c2:00:00:0x to the CPU port.
*/
REG_WRITE(REG_GLOBAL2, 0x03, 0xffff);
- /*
- * Ignore removed tag data on doubly tagged packets, disable
+ /* Ignore removed tag data on doubly tagged packets, disable
* flow control messages, force flow control priority to the
* highest, and send all special multicast frames to the CPU
* port at the highest priority.
*/
REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff);
- /*
- * Program the DSA routing table.
- */
+ /* Program the DSA routing table. */
for (i = 0; i < 32; i++) {
int nexthop;
@@ -155,20 +133,15 @@ static int mv88e6131_setup_global(struct dsa_switch *ds)
REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | nexthop);
}
- /*
- * Clear all trunk masks.
- */
+ /* Clear all trunk masks. */
for (i = 0; i < 8; i++)
REG_WRITE(REG_GLOBAL2, 0x07, 0x8000 | (i << 12) | 0x7ff);
- /*
- * Clear all trunk mappings.
- */
+ /* Clear all trunk mappings. */
for (i = 0; i < 16; i++)
REG_WRITE(REG_GLOBAL2, 0x08, 0x8000 | (i << 11));
- /*
- * Force the priority of IGMP/MLD snoop frames and ARP frames
+ /* Force the priority of IGMP/MLD snoop frames and ARP frames
* to the highest setting.
*/
REG_WRITE(REG_GLOBAL2, 0x0f, 0x00ff);
@@ -182,8 +155,7 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
int addr = REG_PORT(p);
u16 val;
- /*
- * MAC Forcing register: don't force link, speed, duplex
+ /* MAC Forcing register: don't force link, speed, duplex
* or flow control state to any particular values on physical
* ports, but force the CPU port and all DSA ports to 1000 Mb/s
* (100 Mb/s on 6085) full duplex.
@@ -196,8 +168,7 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
else
REG_WRITE(addr, 0x01, 0x0003);
- /*
- * Port Control: disable Core Tag, disable Drop-on-Lock,
+ /* Port Control: disable Core Tag, disable Drop-on-Lock,
* transmit frames unmodified, disable Header mode,
* enable IGMP/MLD snoop, disable DoubleTag, disable VLAN
* tunneling, determine priority by looking at 802.1p and
@@ -214,8 +185,7 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
val = 0x0433;
if (p == dsa_upstream_port(ds)) {
val |= 0x0104;
- /*
- * On 6085, unknown multicast forward is controlled
+ /* On 6085, unknown multicast forward is controlled
* here rather than in Port Control 2 register.
*/
if (ps->id == ID_6085)
@@ -225,14 +195,12 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
val |= 0x0100;
REG_WRITE(addr, 0x04, val);
- /*
- * Port Control 1: disable trunking. Also, if this is the
+ /* Port Control 1: disable trunking. Also, if this is the
* CPU port, enable learn messages to be sent to this port.
*/
REG_WRITE(addr, 0x05, dsa_is_cpu_port(ds, p) ? 0x8000 : 0x0000);
- /*
- * Port based VLAN map: give each port its own address
+ /* Port based VLAN map: give each port its own address
* database, allow the CPU port to talk to each of the 'real'
* ports, and allow each of the 'real' ports to only talk to
* the upstream port.
@@ -244,14 +212,12 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
val |= 1 << dsa_upstream_port(ds);
REG_WRITE(addr, 0x06, val);
- /*
- * Default VLAN ID and priority: don't set a default VLAN
+ /* Default VLAN ID and priority: don't set a default VLAN
* ID, and set the default packet priority to zero.
*/
REG_WRITE(addr, 0x07, 0x0000);
- /*
- * Port Control 2: don't force a good FCS, don't use
+ /* Port Control 2: don't force a good FCS, don't use
* VLAN-based, source address-based or destination
* address-based priority overrides, don't let the switch
* add or strip 802.1q tags, don't discard tagged or
@@ -264,8 +230,7 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
* forwarding of unknown multicast addresses.
*/
if (ps->id == ID_6085)
- /*
- * on 6085, bits 3:0 are reserved, bit 6 control ARP
+ /* on 6085, bits 3:0 are reserved, bit 6 control ARP
* mirroring, and multicast forward is handled in
* Port Control register.
*/
@@ -277,32 +242,25 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
REG_WRITE(addr, 0x08, val);
}
- /*
- * Rate Control: disable ingress rate limiting.
- */
+ /* Rate Control: disable ingress rate limiting. */
REG_WRITE(addr, 0x09, 0x0000);
- /*
- * Rate Control 2: disable egress rate limiting.
- */
+ /* Rate Control 2: disable egress rate limiting. */
REG_WRITE(addr, 0x0a, 0x0000);
- /*
- * Port Association Vector: when learning source addresses
+ /* Port Association Vector: when learning source addresses
* of packets, add the address to the address database using
* a port bitmap that has only the bit for this port set and
* the other bits clear.
*/
REG_WRITE(addr, 0x0b, 1 << p);
- /*
- * Tag Remap: use an identity 802.1p prio -> switch prio
+ /* Tag Remap: use an identity 802.1p prio -> switch prio
* mapping.
*/
REG_WRITE(addr, 0x18, 0x3210);
- /*
- * Tag Remap 2: use an identity 802.1p prio -> switch prio
+ /* Tag Remap 2: use an identity 802.1p prio -> switch prio
* mapping.
*/
REG_WRITE(addr, 0x19, 0x7654);
diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c
index a2c62c2..d436668 100644
--- a/drivers/net/dsa/mv88e6xxx.c
+++ b/drivers/net/dsa/mv88e6xxx.c
@@ -15,8 +15,7 @@
#include <net/dsa.h>
#include "mv88e6xxx.h"
-/*
- * If the switch's ADDR[4:0] strap pins are strapped to zero, it will
+/* If the switch's ADDR[4:0] strap pins are strapped to zero, it will
* use all 32 SMI bus addresses on its SMI bus, and all switch registers
* will be directly accessible on some {device address,register address}
* pair. If the ADDR[4:0] pins are not strapped to zero, the switch
@@ -48,30 +47,22 @@ int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg)
if (sw_addr == 0)
return mdiobus_read(bus, addr, reg);
- /*
- * Wait for the bus to become free.
- */
+ /* Wait for the bus to become free. */
ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
if (ret < 0)
return ret;
- /*
- * Transmit the read command.
- */
+ /* Transmit the read command. */
ret = mdiobus_write(bus, sw_addr, 0, 0x9800 | (addr << 5) | reg);
if (ret < 0)
return ret;
- /*
- * Wait for the read command to complete.
- */
+ /* Wait for the read command to complete. */
ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
if (ret < 0)
return ret;
- /*
- * Read the data.
- */
+ /* Read the data. */
ret = mdiobus_read(bus, sw_addr, 1);
if (ret < 0)
return ret;
@@ -100,30 +91,22 @@ int __mv88e6xxx_reg_write(struct mii_bus *bus, int sw_addr, int addr,
if (sw_addr == 0)
return mdiobus_write(bus, addr, reg, val);
- /*
- * Wait for the bus to become free.
- */
+ /* Wait for the bus to become free. */
ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
if (ret < 0)
return ret;
- /*
- * Transmit the data to write.
- */
+ /* Transmit the data to write. */
ret = mdiobus_write(bus, sw_addr, 1, val);
if (ret < 0)
return ret;
- /*
- * Transmit the write command.
- */
+ /* Transmit the write command. */
ret = mdiobus_write(bus, sw_addr, 0, 0x9400 | (addr << 5) | reg);
if (ret < 0)
return ret;
- /*
- * Wait for the write command to complete.
- */
+ /* Wait for the write command to complete. */
ret = mv88e6xxx_reg_wait_ready(bus, sw_addr);
if (ret < 0)
return ret;
@@ -146,9 +129,7 @@ int mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg, u16 val)
int mv88e6xxx_config_prio(struct dsa_switch *ds)
{
- /*
- * Configure the IP ToS mapping registers.
- */
+ /* Configure the IP ToS mapping registers. */
REG_WRITE(REG_GLOBAL, 0x10, 0x0000);
REG_WRITE(REG_GLOBAL, 0x11, 0x0000);
REG_WRITE(REG_GLOBAL, 0x12, 0x5555);
@@ -158,9 +139,7 @@ int mv88e6xxx_config_prio(struct dsa_switch *ds)
REG_WRITE(REG_GLOBAL, 0x16, 0xffff);
REG_WRITE(REG_GLOBAL, 0x17, 0xffff);
- /*
- * Configure the IEEE 802.1p priority mapping register.
- */
+ /* Configure the IEEE 802.1p priority mapping register. */
REG_WRITE(REG_GLOBAL, 0x18, 0xfa41);
return 0;
@@ -183,14 +162,10 @@ int mv88e6xxx_set_addr_indirect(struct dsa_switch *ds, u8 *addr)
for (i = 0; i < 6; i++) {
int j;
- /*
- * Write the MAC address byte.
- */
+ /* Write the MAC address byte. */
REG_WRITE(REG_GLOBAL2, 0x0d, 0x8000 | (i << 8) | addr[i]);
- /*
- * Wait for the write to complete.
- */
+ /* Wait for the write to complete. */
for (j = 0; j < 16; j++) {
ret = REG_READ(REG_GLOBAL2, 0x0d);
if ((ret & 0x8000) == 0)
@@ -282,8 +257,7 @@ static int mv88e6xxx_ppu_access_get(struct dsa_switch *ds)
mutex_lock(&ps->ppu_mutex);
- /*
- * If the PHY polling unit is enabled, disable it so that
+ /* If the PHY polling unit is enabled, disable it so that
* we can access the PHY registers. If it was already
* disabled, cancel the timer that is going to re-enable
* it.
@@ -307,9 +281,7 @@ static void mv88e6xxx_ppu_access_put(struct dsa_switch *ds)
{
struct mv88e6xxx_priv_state *ps = (void *)(ds + 1);
- /*
- * Schedule a timer to re-enable the PHY polling unit.
- */
+ /* Schedule a timer to re-enable the PHY polling unit. */
mod_timer(&ps->ppu_timer, jiffies + msecs_to_jiffies(10));
mutex_unlock(&ps->ppu_mutex);
}
@@ -431,14 +403,10 @@ static int mv88e6xxx_stats_snapshot(struct dsa_switch *ds, int port)
{
int ret;
- /*
- * Snapshot the hardware statistics counters for this port.
- */
+ /* Snapshot the hardware statistics counters for this port. */
REG_WRITE(REG_GLOBAL, 0x1d, 0xdc00 | port);
- /*
- * Wait for the snapshotting to complete.
- */
+ /* Wait for the snapshotting to complete. */
ret = mv88e6xxx_stats_wait(ds);
if (ret < 0)
return ret;
@@ -502,9 +470,7 @@ void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds,
return;
}
- /*
- * Read each of the counters.
- */
+ /* Read each of the counters. */
for (i = 0; i < nr_stats; i++) {
struct mv88e6xxx_hw_stat *s = stats + i;
u32 low;
diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h
index fc2cd7b..029e13d 100644
--- a/drivers/net/dsa/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx.h
@@ -16,16 +16,14 @@
#define REG_GLOBAL2 0x1c
struct mv88e6xxx_priv_state {
- /*
- * When using multi-chip addressing, this mutex protects
+ /* When using multi-chip addressing, this mutex protects
* access to the indirect access registers. (In single-chip
* mode, this mutex is effectively useless.)
*/
struct mutex smi_mutex;
#ifdef CONFIG_NET_DSA_MV88E6XXX_NEED_PPU
- /*
- * Handles automatic disabling and re-enabling of the PHY
+ /* Handles automatic disabling and re-enabling of the PHY
* polling unit.
*/
struct mutex ppu_mutex;
@@ -34,8 +32,7 @@ struct mv88e6xxx_priv_state {
struct timer_list ppu_timer;
#endif
- /*
- * This mutex serialises access to the statistics unit.
+ /* This mutex serialises access to the statistics unit.
* Hold this mutex over snapshot + dump sequences.
*/
struct mutex stats_mutex;
--
1.7.9.5
^ permalink raw reply related
* [PATCH V2 2/4] DSA: Convert repeated msleep calls to timeouts
From: Barry Grussling @ 2013-01-09 2:05 UTC (permalink / raw)
To: netdev; +Cc: Barry Grussling
In-Reply-To: <1357697156-5767-1-git-send-email-barry@grussling.com>
From: Barry Grussling <barry@grussling.com>
Convert DSA msleep calls to timeout/usleep_range calls
as reported by checkpatch.pl.
Signed-off-by: Barry Grussling <barry@grussling.com>
---
drivers/net/dsa/mv88e6060.c | 12 ++++++++----
drivers/net/dsa/mv88e6123_61_65.c | 12 ++++++++----
drivers/net/dsa/mv88e6131.c | 12 ++++++++----
drivers/net/dsa/mv88e6xxx.c | 16 ++++++++++------
4 files changed, 34 insertions(+), 18 deletions(-)
diff --git a/drivers/net/dsa/mv88e6060.c b/drivers/net/dsa/mv88e6060.c
index 637373c..8548f8d 100644
--- a/drivers/net/dsa/mv88e6060.c
+++ b/drivers/net/dsa/mv88e6060.c
@@ -8,6 +8,8 @@
* (at your option) any later version.
*/
+#include <linux/delay.h>
+#include <linux/jiffies.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/netdevice.h>
@@ -66,6 +68,7 @@ static int mv88e6060_switch_reset(struct dsa_switch *ds)
{
int i;
int ret;
+ unsigned long timeout;
/* Set all ports to the disabled state. */
for (i = 0; i < 6; i++) {
@@ -74,20 +77,21 @@ static int mv88e6060_switch_reset(struct dsa_switch *ds)
}
/* Wait for transmit queues to drain. */
- msleep(2);
+ usleep_range(2000, 4000);
/* Reset the switch. */
REG_WRITE(REG_GLOBAL, 0x0a, 0xa130);
/* Wait up to one second for reset to complete. */
- for (i = 0; i < 1000; i++) {
+ timeout = jiffies + 1 * HZ;
+ while (time_before(jiffies, timeout)) {
ret = REG_READ(REG_GLOBAL, 0x00);
if ((ret & 0x8000) == 0x0000)
break;
- msleep(1);
+ usleep_range(1000, 2000);
}
- if (i == 1000)
+ if (time_after(jiffies, timeout))
return -ETIMEDOUT;
return 0;
diff --git a/drivers/net/dsa/mv88e6123_61_65.c b/drivers/net/dsa/mv88e6123_61_65.c
index a644fc9..41ee5b6 100644
--- a/drivers/net/dsa/mv88e6123_61_65.c
+++ b/drivers/net/dsa/mv88e6123_61_65.c
@@ -8,6 +8,8 @@
* (at your option) any later version.
*/
+#include <linux/delay.h>
+#include <linux/jiffies.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/netdevice.h>
@@ -50,6 +52,7 @@ static int mv88e6123_61_65_switch_reset(struct dsa_switch *ds)
{
int i;
int ret;
+ unsigned long timeout;
/* Set all ports to the disabled state. */
for (i = 0; i < 8; i++) {
@@ -58,20 +61,21 @@ static int mv88e6123_61_65_switch_reset(struct dsa_switch *ds)
}
/* Wait for transmit queues to drain. */
- msleep(2);
+ usleep_range(2000, 4000);
/* Reset the switch. */
REG_WRITE(REG_GLOBAL, 0x04, 0xc400);
/* Wait up to one second for reset to complete. */
- for (i = 0; i < 1000; i++) {
+ timeout = jiffies + 1 * HZ;
+ while (time_before(jiffies, timeout)) {
ret = REG_READ(REG_GLOBAL, 0x00);
if ((ret & 0xc800) == 0xc800)
break;
- msleep(1);
+ usleep_range(1000, 2000);
}
- if (i == 1000)
+ if (time_after(jiffies, timeout))
return -ETIMEDOUT;
return 0;
diff --git a/drivers/net/dsa/mv88e6131.c b/drivers/net/dsa/mv88e6131.c
index b613818..dadfafb 100644
--- a/drivers/net/dsa/mv88e6131.c
+++ b/drivers/net/dsa/mv88e6131.c
@@ -8,6 +8,8 @@
* (at your option) any later version.
*/
+#include <linux/delay.h>
+#include <linux/jiffies.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/netdevice.h>
@@ -42,6 +44,7 @@ static int mv88e6131_switch_reset(struct dsa_switch *ds)
{
int i;
int ret;
+ unsigned long timeout;
/* Set all ports to the disabled state. */
for (i = 0; i < 11; i++) {
@@ -50,20 +53,21 @@ static int mv88e6131_switch_reset(struct dsa_switch *ds)
}
/* Wait for transmit queues to drain. */
- msleep(2);
+ usleep_range(2000, 4000);
/* Reset the switch. */
REG_WRITE(REG_GLOBAL, 0x04, 0xc400);
/* Wait up to one second for reset to complete. */
- for (i = 0; i < 1000; i++) {
+ timeout = jiffies + 1 * HZ;
+ while (time_before(jiffies, timeout)) {
ret = REG_READ(REG_GLOBAL, 0x00);
if ((ret & 0xc800) == 0xc800)
break;
- msleep(1);
+ usleep_range(1000, 2000);
}
- if (i == 1000)
+ if (time_after(jiffies, timeout))
return -ETIMEDOUT;
return 0;
diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c
index d436668..afe7d80 100644
--- a/drivers/net/dsa/mv88e6xxx.c
+++ b/drivers/net/dsa/mv88e6xxx.c
@@ -8,6 +8,8 @@
* (at your option) any later version.
*/
+#include <linux/delay.h>
+#include <linux/jiffies.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/netdevice.h>
@@ -196,14 +198,15 @@ int mv88e6xxx_phy_write(struct dsa_switch *ds, int addr, int regnum, u16 val)
static int mv88e6xxx_ppu_disable(struct dsa_switch *ds)
{
int ret;
- int i;
+ unsigned long timeout;
ret = REG_READ(REG_GLOBAL, 0x04);
REG_WRITE(REG_GLOBAL, 0x04, ret & ~0x4000);
- for (i = 0; i < 1000; i++) {
+ timeout = jiffies + 1 * HZ;
+ while (time_before(jiffies, timeout)) {
ret = REG_READ(REG_GLOBAL, 0x00);
- msleep(1);
+ usleep_range(1000, 2000);
if ((ret & 0xc000) != 0xc000)
return 0;
}
@@ -214,14 +217,15 @@ static int mv88e6xxx_ppu_disable(struct dsa_switch *ds)
static int mv88e6xxx_ppu_enable(struct dsa_switch *ds)
{
int ret;
- int i;
+ unsigned long timeout;
ret = REG_READ(REG_GLOBAL, 0x04);
REG_WRITE(REG_GLOBAL, 0x04, ret | 0x4000);
- for (i = 0; i < 1000; i++) {
+ timeout = jiffies + 1 * HZ;
+ while (time_before(jiffies, timeout)) {
ret = REG_READ(REG_GLOBAL, 0x00);
- msleep(1);
+ usleep_range(1000, 2000);
if ((ret & 0xc000) == 0xc000)
return 0;
}
--
1.7.9.5
^ permalink raw reply related
* [PATCH V2 3/4] DSA: Convert printk calls to netdev_info calls
From: Barry Grussling @ 2013-01-09 2:05 UTC (permalink / raw)
To: netdev; +Cc: Barry Grussling
In-Reply-To: <1357697156-5767-1-git-send-email-barry@grussling.com>
From: Barry Grussling <barry@grussling.com>
Convert DSA printk calls to netdev_info calls as recommended by
checkpatch.pl.
Signed-off-by: Barry Grussling <barry@grussling.com>
---
drivers/net/dsa/mv88e6060.c | 11 ++++++-----
drivers/net/dsa/mv88e6xxx.c | 11 ++++++-----
2 files changed, 12 insertions(+), 10 deletions(-)
diff --git a/drivers/net/dsa/mv88e6060.c b/drivers/net/dsa/mv88e6060.c
index 8548f8d..7a54ec0 100644
--- a/drivers/net/dsa/mv88e6060.c
+++ b/drivers/net/dsa/mv88e6060.c
@@ -236,7 +236,7 @@ static void mv88e6060_poll_link(struct dsa_switch *ds)
if (!link) {
if (netif_carrier_ok(dev)) {
- printk(KERN_INFO "%s: link down\n", dev->name);
+ netdev_info(dev, "link down\n");
netif_carrier_off(dev);
}
continue;
@@ -247,10 +247,11 @@ static void mv88e6060_poll_link(struct dsa_switch *ds)
fc = ((port_status & 0xc000) == 0xc000) ? 1 : 0;
if (!netif_carrier_ok(dev)) {
- printk(KERN_INFO "%s: link up, %d Mb/s, %s duplex, "
- "flow control %sabled\n", dev->name,
- speed, duplex ? "full" : "half",
- fc ? "en" : "dis");
+ netdev_info(dev,
+ "link up, %d Mb/s, %s duplex, flow control %sabled\n",
+ speed,
+ duplex ? "full" : "half",
+ fc ? "en" : "dis");
netif_carrier_on(dev);
}
}
diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c
index afe7d80..3756c74 100644
--- a/drivers/net/dsa/mv88e6xxx.c
+++ b/drivers/net/dsa/mv88e6xxx.c
@@ -356,7 +356,7 @@ void mv88e6xxx_poll_link(struct dsa_switch *ds)
if (!link) {
if (netif_carrier_ok(dev)) {
- printk(KERN_INFO "%s: link down\n", dev->name);
+ netdev_info(dev, "link down\n");
netif_carrier_off(dev);
}
continue;
@@ -380,10 +380,11 @@ void mv88e6xxx_poll_link(struct dsa_switch *ds)
fc = (port_status & 0x8000) ? 1 : 0;
if (!netif_carrier_ok(dev)) {
- printk(KERN_INFO "%s: link up, %d Mb/s, %s duplex, "
- "flow control %sabled\n", dev->name,
- speed, duplex ? "full" : "half",
- fc ? "en" : "dis");
+ netdev_info(dev,
+ "link up, %d Mb/s, %s duplex, flow control %sabled\n",
+ speed,
+ duplex ? "full" : "half",
+ fc ? "en" : "dis");
netif_carrier_on(dev);
}
}
--
1.7.9.5
^ permalink raw reply related
* [PATCH V2 4/4] DSA: Convert spaces to tabs where appropriate
From: Barry Grussling @ 2013-01-09 2:05 UTC (permalink / raw)
To: netdev; +Cc: Barry Grussling
In-Reply-To: <1357697156-5767-1-git-send-email-barry@grussling.com>
From: Barry Grussling <barry@grussling.com>
Fix DSA whitespace issues reported by checkpatch.pl
Signed-off-by: Barry Grussling <barry@grussling.com>
---
drivers/net/dsa/mv88e6xxx.c | 44 +++++++++++++++++++++----------------------
drivers/net/dsa/mv88e6xxx.h | 2 +-
2 files changed, 23 insertions(+), 23 deletions(-)
diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c
index 3756c74..17314ed 100644
--- a/drivers/net/dsa/mv88e6xxx.c
+++ b/drivers/net/dsa/mv88e6xxx.c
@@ -205,10 +205,10 @@ static int mv88e6xxx_ppu_disable(struct dsa_switch *ds)
timeout = jiffies + 1 * HZ;
while (time_before(jiffies, timeout)) {
- ret = REG_READ(REG_GLOBAL, 0x00);
+ ret = REG_READ(REG_GLOBAL, 0x00);
usleep_range(1000, 2000);
- if ((ret & 0xc000) != 0xc000)
- return 0;
+ if ((ret & 0xc000) != 0xc000)
+ return 0;
}
return -ETIMEDOUT;
@@ -224,10 +224,10 @@ static int mv88e6xxx_ppu_enable(struct dsa_switch *ds)
timeout = jiffies + 1 * HZ;
while (time_before(jiffies, timeout)) {
- ret = REG_READ(REG_GLOBAL, 0x00);
+ ret = REG_READ(REG_GLOBAL, 0x00);
usleep_range(1000, 2000);
- if ((ret & 0xc000) == 0xc000)
- return 0;
+ if ((ret & 0xc000) == 0xc000)
+ return 0;
}
return -ETIMEDOUT;
@@ -239,11 +239,11 @@ static void mv88e6xxx_ppu_reenable_work(struct work_struct *ugly)
ps = container_of(ugly, struct mv88e6xxx_priv_state, ppu_work);
if (mutex_trylock(&ps->ppu_mutex)) {
- struct dsa_switch *ds = ((struct dsa_switch *)ps) - 1;
+ struct dsa_switch *ds = ((struct dsa_switch *)ps) - 1;
- if (mv88e6xxx_ppu_enable(ds) == 0)
- ps->ppu_disabled = 0;
- mutex_unlock(&ps->ppu_mutex);
+ if (mv88e6xxx_ppu_enable(ds) == 0)
+ ps->ppu_disabled = 0;
+ mutex_unlock(&ps->ppu_mutex);
}
}
@@ -267,15 +267,15 @@ static int mv88e6xxx_ppu_access_get(struct dsa_switch *ds)
* it.
*/
if (!ps->ppu_disabled) {
- ret = mv88e6xxx_ppu_disable(ds);
- if (ret < 0) {
- mutex_unlock(&ps->ppu_mutex);
- return ret;
- }
- ps->ppu_disabled = 1;
+ ret = mv88e6xxx_ppu_disable(ds);
+ if (ret < 0) {
+ mutex_unlock(&ps->ppu_mutex);
+ return ret;
+ }
+ ps->ppu_disabled = 1;
} else {
- del_timer(&ps->ppu_timer);
- ret = 0;
+ del_timer(&ps->ppu_timer);
+ ret = 0;
}
return ret;
@@ -307,8 +307,8 @@ int mv88e6xxx_phy_read_ppu(struct dsa_switch *ds, int addr, int regnum)
ret = mv88e6xxx_ppu_access_get(ds);
if (ret >= 0) {
- ret = mv88e6xxx_reg_read(ds, addr, regnum);
- mv88e6xxx_ppu_access_put(ds);
+ ret = mv88e6xxx_reg_read(ds, addr, regnum);
+ mv88e6xxx_ppu_access_put(ds);
}
return ret;
@@ -321,8 +321,8 @@ int mv88e6xxx_phy_write_ppu(struct dsa_switch *ds, int addr,
ret = mv88e6xxx_ppu_access_get(ds);
if (ret >= 0) {
- ret = mv88e6xxx_reg_write(ds, addr, regnum, val);
- mv88e6xxx_ppu_access_put(ds);
+ ret = mv88e6xxx_reg_write(ds, addr, regnum, val);
+ mv88e6xxx_ppu_access_put(ds);
}
return ret;
diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h
index 029e13d..911ede5 100644
--- a/drivers/net/dsa/mv88e6xxx.h
+++ b/drivers/net/dsa/mv88e6xxx.h
@@ -49,7 +49,7 @@ struct mv88e6xxx_hw_stat {
int __mv88e6xxx_reg_read(struct mii_bus *bus, int sw_addr, int addr, int reg);
int mv88e6xxx_reg_read(struct dsa_switch *ds, int addr, int reg);
int __mv88e6xxx_reg_write(struct mii_bus *bus, int sw_addr, int addr,
- int reg, u16 val);
+ int reg, u16 val);
int mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg, u16 val);
int mv88e6xxx_config_prio(struct dsa_switch *ds);
int mv88e6xxx_set_addr_direct(struct dsa_switch *ds, u8 *addr);
--
1.7.9.5
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox