Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[cascardo/linux.git] / drivers / net / hyperv / netvsc.c
index 410fb8e..720b5fa 100644 (file)
@@ -59,7 +59,6 @@ void netvsc_switch_datapath(struct net_device *ndev, bool vf)
                               VM_PKT_DATA_INBAND, 0);
 }
 
-
 static struct netvsc_device *alloc_net_device(void)
 {
        struct netvsc_device *net_device;
@@ -74,17 +73,26 @@ static struct netvsc_device *alloc_net_device(void)
                return NULL;
        }
 
+       net_device->mrc[0].buf = vzalloc(NETVSC_RECVSLOT_MAX *
+                                        sizeof(struct recv_comp_data));
+
        init_waitqueue_head(&net_device->wait_drain);
        net_device->destroy = false;
        atomic_set(&net_device->open_cnt, 0);
        net_device->max_pkt = RNDIS_MAX_PKT_DEFAULT;
        net_device->pkt_align = RNDIS_PKT_ALIGN_DEFAULT;
+       init_completion(&net_device->channel_init_wait);
 
        return net_device;
 }
 
 static void free_netvsc_device(struct netvsc_device *nvdev)
 {
+       int i;
+
+       for (i = 0; i < VRSS_CHANNEL_MAX; i++)
+               vfree(nvdev->mrc[i].buf);
+
        kfree(nvdev->cb_buffer);
        kfree(nvdev);
 }
@@ -107,20 +115,20 @@ static struct netvsc_device *get_inbound_net_device(struct hv_device *device)
                goto get_in_err;
 
        if (net_device->destroy &&
-               atomic_read(&net_device->num_outstanding_sends) == 0)
+           atomic_read(&net_device->num_outstanding_sends) == 0 &&
+           atomic_read(&net_device->num_outstanding_recvs) == 0)
                net_device = NULL;
 
 get_in_err:
        return net_device;
 }
 
-
-static int netvsc_destroy_buf(struct hv_device *device)
+static void netvsc_destroy_buf(struct hv_device *device)
 {
        struct nvsp_message *revoke_packet;
-       int ret = 0;
        struct net_device *ndev = hv_get_drvdata(device);
        struct netvsc_device *net_device = net_device_to_netvsc_device(ndev);
+       int ret;
 
        /*
         * If we got a section count, it means we received a
@@ -150,7 +158,7 @@ static int netvsc_destroy_buf(struct hv_device *device)
                if (ret != 0) {
                        netdev_err(ndev, "unable to send "
                                "revoke receive buffer to netvsp\n");
-                       return ret;
+                       return;
                }
        }
 
@@ -165,7 +173,7 @@ static int netvsc_destroy_buf(struct hv_device *device)
                if (ret != 0) {
                        netdev_err(ndev,
                                   "unable to teardown receive buffer's gpadl\n");
-                       return ret;
+                       return;
                }
                net_device->recv_buf_gpadl_handle = 0;
        }
@@ -209,7 +217,7 @@ static int netvsc_destroy_buf(struct hv_device *device)
                if (ret != 0) {
                        netdev_err(ndev, "unable to send "
                                   "revoke send buffer to netvsp\n");
-                       return ret;
+                       return;
                }
        }
        /* Teardown the gpadl on the vsp end */
@@ -223,7 +231,7 @@ static int netvsc_destroy_buf(struct hv_device *device)
                if (ret != 0) {
                        netdev_err(ndev,
                                   "unable to teardown send buffer's gpadl\n");
-                       return ret;
+                       return;
                }
                net_device->send_buf_gpadl_handle = 0;
        }
@@ -233,8 +241,6 @@ static int netvsc_destroy_buf(struct hv_device *device)
                net_device->send_buf = NULL;
        }
        kfree(net_device->send_section_map);
-
-       return ret;
 }
 
 static int netvsc_init_buf(struct hv_device *device)
@@ -276,7 +282,6 @@ static int netvsc_init_buf(struct hv_device *device)
                goto cleanup;
        }
 
-
        /* Notify the NetVsp of the gpadl handle */
        init_packet = &net_device->channel_init_pkt;
 
@@ -403,7 +408,7 @@ static int netvsc_init_buf(struct hv_device *device)
        /* Section count is simply the size divided by the section size.
         */
        net_device->send_section_cnt =
-               net_device->send_buf_size/net_device->send_section_size;
+               net_device->send_buf_size / net_device->send_section_size;
 
        dev_info(&device->device, "Send section size: %d, Section count:%d\n",
                 net_device->send_section_size, net_device->send_section_cnt);
@@ -412,8 +417,8 @@ static int netvsc_init_buf(struct hv_device *device)
        net_device->map_words = DIV_ROUND_UP(net_device->send_section_cnt,
                                             BITS_PER_LONG);
 
-       net_device->send_section_map =
-               kzalloc(net_device->map_words * sizeof(ulong), GFP_KERNEL);
+       net_device->send_section_map = kcalloc(net_device->map_words,
+                                              sizeof(ulong), GFP_KERNEL);
        if (net_device->send_section_map == NULL) {
                ret = -ENOMEM;
                goto cleanup;
@@ -428,7 +433,6 @@ exit:
        return ret;
 }
 
-
 /* Negotiate NVSP protocol version */
 static int negotiate_nvsp_ver(struct hv_device *device,
                              struct netvsc_device *net_device,
@@ -468,9 +472,13 @@ static int negotiate_nvsp_ver(struct hv_device *device,
        init_packet->msg.v2_msg.send_ndis_config.mtu = ndev->mtu + ETH_HLEN;
        init_packet->msg.v2_msg.send_ndis_config.capability.ieee8021q = 1;
 
-       if (nvsp_ver >= NVSP_PROTOCOL_VERSION_5)
+       if (nvsp_ver >= NVSP_PROTOCOL_VERSION_5) {
                init_packet->msg.v2_msg.send_ndis_config.capability.sriov = 1;
 
+               /* Teaming bit is needed to receive link speed updates */
+               init_packet->msg.v2_msg.send_ndis_config.capability.teaming = 1;
+       }
+
        ret = vmbus_sendpacket(device->channel, init_packet,
                                sizeof(struct nvsp_message),
                                (unsigned long)init_packet,
@@ -485,9 +493,10 @@ static int netvsc_connect_vsp(struct hv_device *device)
        struct netvsc_device *net_device;
        struct nvsp_message *init_packet;
        int ndis_version;
-       u32 ver_list[] = { NVSP_PROTOCOL_VERSION_1, NVSP_PROTOCOL_VERSION_2,
+       const u32 ver_list[] = {
+               NVSP_PROTOCOL_VERSION_1, NVSP_PROTOCOL_VERSION_2,
                NVSP_PROTOCOL_VERSION_4, NVSP_PROTOCOL_VERSION_5 };
-       int i, num_ver = 4; /* number of different NVSP versions */
+       int i;
 
        net_device = get_outbound_net_device(device);
        if (!net_device)
@@ -496,7 +505,7 @@ static int netvsc_connect_vsp(struct hv_device *device)
        init_packet = &net_device->channel_init_pkt;
 
        /* Negotiate the latest NVSP protocol supported */
-       for (i = num_ver - 1; i >= 0; i--)
+       for (i = ARRAY_SIZE(ver_list) - 1; i >= 0; i--)
                if (negotiate_nvsp_ver(device, net_device, init_packet,
                                       ver_list[i])  == 0) {
                        net_device->nvsp_version = ver_list[i];
@@ -555,7 +564,7 @@ static void netvsc_disconnect_vsp(struct hv_device *device)
 /*
  * netvsc_device_remove - Callback when the root bus device is removed
  */
-int netvsc_device_remove(struct hv_device *device)
+void netvsc_device_remove(struct hv_device *device)
 {
        struct net_device *ndev = hv_get_drvdata(device);
        struct net_device_context *net_device_ctx = netdev_priv(ndev);
@@ -577,10 +586,8 @@ int netvsc_device_remove(struct hv_device *device)
        /* Release all resources */
        vfree(net_device->sub_cb_buf);
        free_netvsc_device(net_device);
-       return 0;
 }
 
-
 #define RING_AVAIL_PERCENT_HIWATER 20
 #define RING_AVAIL_PERCENT_LOWATER 10
 
@@ -604,72 +611,79 @@ static inline void netvsc_free_send_slot(struct netvsc_device *net_device,
        sync_change_bit(index, net_device->send_section_map);
 }
 
+static void netvsc_send_tx_complete(struct netvsc_device *net_device,
+                                   struct vmbus_channel *incoming_channel,
+                                   struct hv_device *device,
+                                   struct vmpacket_descriptor *packet)
+{
+       struct sk_buff *skb = (struct sk_buff *)(unsigned long)packet->trans_id;
+       struct net_device *ndev = hv_get_drvdata(device);
+       struct net_device_context *net_device_ctx = netdev_priv(ndev);
+       struct vmbus_channel *channel = device->channel;
+       int num_outstanding_sends;
+       u16 q_idx = 0;
+       int queue_sends;
+
+       /* Notify the layer above us */
+       if (likely(skb)) {
+               struct hv_netvsc_packet *nvsc_packet
+                       = (struct hv_netvsc_packet *)skb->cb;
+               u32 send_index = nvsc_packet->send_buf_index;
+
+               if (send_index != NETVSC_INVALID_INDEX)
+                       netvsc_free_send_slot(net_device, send_index);
+               q_idx = nvsc_packet->q_idx;
+               channel = incoming_channel;
+
+               dev_consume_skb_any(skb);
+       }
+
+       num_outstanding_sends =
+               atomic_dec_return(&net_device->num_outstanding_sends);
+       queue_sends = atomic_dec_return(&net_device->queue_sends[q_idx]);
+
+       if (net_device->destroy && num_outstanding_sends == 0)
+               wake_up(&net_device->wait_drain);
+
+       if (netif_tx_queue_stopped(netdev_get_tx_queue(ndev, q_idx)) &&
+           !net_device_ctx->start_remove &&
+           (hv_ringbuf_avail_percent(&channel->outbound) > RING_AVAIL_PERCENT_HIWATER ||
+            queue_sends < 1))
+               netif_tx_wake_queue(netdev_get_tx_queue(ndev, q_idx));
+}
+
 static void netvsc_send_completion(struct netvsc_device *net_device,
                                   struct vmbus_channel *incoming_channel,
                                   struct hv_device *device,
                                   struct vmpacket_descriptor *packet)
 {
        struct nvsp_message *nvsp_packet;
-       struct hv_netvsc_packet *nvsc_packet;
        struct net_device *ndev = hv_get_drvdata(device);
-       struct net_device_context *net_device_ctx = netdev_priv(ndev);
-       u32 send_index;
-       struct sk_buff *skb;
 
        nvsp_packet = (struct nvsp_message *)((unsigned long)packet +
-                       (packet->offset8 << 3));
+                                             (packet->offset8 << 3));
 
-       if ((nvsp_packet->hdr.msg_type == NVSP_MSG_TYPE_INIT_COMPLETE) ||
-           (nvsp_packet->hdr.msg_type ==
-            NVSP_MSG1_TYPE_SEND_RECV_BUF_COMPLETE) ||
-           (nvsp_packet->hdr.msg_type ==
-            NVSP_MSG1_TYPE_SEND_SEND_BUF_COMPLETE) ||
-           (nvsp_packet->hdr.msg_type ==
-            NVSP_MSG5_TYPE_SUBCHANNEL)) {
+       switch (nvsp_packet->hdr.msg_type) {
+       case NVSP_MSG_TYPE_INIT_COMPLETE:
+       case NVSP_MSG1_TYPE_SEND_RECV_BUF_COMPLETE:
+       case NVSP_MSG1_TYPE_SEND_SEND_BUF_COMPLETE:
+       case NVSP_MSG5_TYPE_SUBCHANNEL:
                /* Copy the response back */
                memcpy(&net_device->channel_init_pkt, nvsp_packet,
                       sizeof(struct nvsp_message));
                complete(&net_device->channel_init_wait);
-       } else if (nvsp_packet->hdr.msg_type ==
-                  NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE) {
-               int num_outstanding_sends;
-               u16 q_idx = 0;
-               struct vmbus_channel *channel = device->channel;
-               int queue_sends;
-
-               /* Get the send context */
-               skb = (struct sk_buff *)(unsigned long)packet->trans_id;
-
-               /* Notify the layer above us */
-               if (skb) {
-                       nvsc_packet = (struct hv_netvsc_packet *) skb->cb;
-                       send_index = nvsc_packet->send_buf_index;
-                       if (send_index != NETVSC_INVALID_INDEX)
-                               netvsc_free_send_slot(net_device, send_index);
-                       q_idx = nvsc_packet->q_idx;
-                       channel = incoming_channel;
-                       dev_kfree_skb_any(skb);
-               }
-
-               num_outstanding_sends =
-                       atomic_dec_return(&net_device->num_outstanding_sends);
-               queue_sends = atomic_dec_return(&net_device->
-                                               queue_sends[q_idx]);
+               break;
 
-               if (net_device->destroy && num_outstanding_sends == 0)
-                       wake_up(&net_device->wait_drain);
+       case NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE:
+               netvsc_send_tx_complete(net_device, incoming_channel,
+                                       device, packet);
+               break;
 
-               if (netif_tx_queue_stopped(netdev_get_tx_queue(ndev, q_idx)) &&
-                   !net_device_ctx->start_remove &&
-                   (hv_ringbuf_avail_percent(&channel->outbound) >
-                    RING_AVAIL_PERCENT_HIWATER || queue_sends < 1))
-                               netif_tx_wake_queue(netdev_get_tx_queue(
-                                                   ndev, q_idx));
-       } else {
-               netdev_err(ndev, "Unknown send completion packet type- "
-                          "%d received!!\n", nvsp_packet->hdr.msg_type);
+       default:
+               netdev_err(ndev,
+                          "Unknown send completion type %d received!!\n",
+                          nvsp_packet->hdr.msg_type);
        }
-
 }
 
 static u32 netvsc_get_next_send_section(struct netvsc_device *net_device)
@@ -859,7 +873,7 @@ int netvsc_send(struct hv_device *device,
                struct sk_buff *skb)
 {
        struct netvsc_device *net_device;
-       int ret = 0, m_ret = 0;
+       int ret = 0;
        struct vmbus_channel *out_channel;
        u16 q_idx = packet->q_idx;
        u32 pktlen = packet->total_data_buflen, msd_len = 0;
@@ -930,7 +944,7 @@ int netvsc_send(struct hv_device *device,
                }
 
                if (msdp->skb)
-                       dev_kfree_skb_any(msdp->skb);
+                       dev_consume_skb_any(msdp->skb);
 
                if (xmit_more && !packet->cp_partial) {
                        msdp->skb = skb;
@@ -948,8 +962,8 @@ int netvsc_send(struct hv_device *device,
        }
 
        if (msd_send) {
-               m_ret = netvsc_send_pkt(device, msd_send, net_device,
-                                       NULL, msd_skb);
+               int m_ret = netvsc_send_pkt(device, msd_send, net_device,
+                                           NULL, msd_skb);
 
                if (m_ret != 0) {
                        netvsc_free_send_slot(net_device,
@@ -968,49 +982,121 @@ send_now:
        return ret;
 }
 
-static void netvsc_send_recv_completion(struct hv_device *device,
-                                       struct vmbus_channel *channel,
-                                       struct netvsc_device *net_device,
-                                       u64 transaction_id, u32 status)
+static int netvsc_send_recv_completion(struct vmbus_channel *channel,
+                                      u64 transaction_id, u32 status)
 {
        struct nvsp_message recvcompMessage;
-       int retries = 0;
        int ret;
-       struct net_device *ndev = hv_get_drvdata(device);
 
        recvcompMessage.hdr.msg_type =
                                NVSP_MSG1_TYPE_SEND_RNDIS_PKT_COMPLETE;
 
        recvcompMessage.msg.v1_msg.send_rndis_pkt_complete.status = status;
 
-retry_send_cmplt:
        /* Send the completion */
        ret = vmbus_sendpacket(channel, &recvcompMessage,
-                              sizeof(struct nvsp_message), transaction_id,
-                              VM_PKT_COMP, 0);
-       if (ret == 0) {
-               /* success */
-               /* no-op */
-       } else if (ret == -EAGAIN) {
-               /* no more room...wait a bit and attempt to retry 3 times */
-               retries++;
-               netdev_err(ndev, "unable to send receive completion pkt"
-                       " (tid %llx)...retrying %d\n", transaction_id, retries);
-
-               if (retries < 4) {
-                       udelay(100);
-                       goto retry_send_cmplt;
-               } else {
-                       netdev_err(ndev, "unable to send receive "
-                               "completion pkt (tid %llx)...give up retrying\n",
-                               transaction_id);
-               }
-       } else {
-               netdev_err(ndev, "unable to send receive "
-                       "completion pkt - %llx\n", transaction_id);
+                              sizeof(struct nvsp_message_header) + sizeof(u32),
+                              transaction_id, VM_PKT_COMP, 0);
+
+       return ret;
+}
+
+static inline void count_recv_comp_slot(struct netvsc_device *nvdev, u16 q_idx,
+                                       u32 *filled, u32 *avail)
+{
+       u32 first = nvdev->mrc[q_idx].first;
+       u32 next = nvdev->mrc[q_idx].next;
+
+       *filled = (first > next) ? NETVSC_RECVSLOT_MAX - first + next :
+                 next - first;
+
+       *avail = NETVSC_RECVSLOT_MAX - *filled - 1;
+}
+
+/* Read the first filled slot, no change to index */
+static inline struct recv_comp_data *read_recv_comp_slot(struct netvsc_device
+                                                        *nvdev, u16 q_idx)
+{
+       u32 filled, avail;
+
+       if (!nvdev->mrc[q_idx].buf)
+               return NULL;
+
+       count_recv_comp_slot(nvdev, q_idx, &filled, &avail);
+       if (!filled)
+               return NULL;
+
+       return nvdev->mrc[q_idx].buf + nvdev->mrc[q_idx].first *
+              sizeof(struct recv_comp_data);
+}
+
+/* Put the first filled slot back to available pool */
+static inline void put_recv_comp_slot(struct netvsc_device *nvdev, u16 q_idx)
+{
+       int num_recv;
+
+       nvdev->mrc[q_idx].first = (nvdev->mrc[q_idx].first + 1) %
+                                 NETVSC_RECVSLOT_MAX;
+
+       num_recv = atomic_dec_return(&nvdev->num_outstanding_recvs);
+
+       if (nvdev->destroy && num_recv == 0)
+               wake_up(&nvdev->wait_drain);
+}
+
+/* Check and send pending recv completions */
+static void netvsc_chk_recv_comp(struct netvsc_device *nvdev,
+                                struct vmbus_channel *channel, u16 q_idx)
+{
+       struct recv_comp_data *rcd;
+       int ret;
+
+       while (true) {
+               rcd = read_recv_comp_slot(nvdev, q_idx);
+               if (!rcd)
+                       break;
+
+               ret = netvsc_send_recv_completion(channel, rcd->tid,
+                                                 rcd->status);
+               if (ret)
+                       break;
+
+               put_recv_comp_slot(nvdev, q_idx);
        }
 }
 
+#define NETVSC_RCD_WATERMARK 80
+
+/* Get next available slot */
+static inline struct recv_comp_data *get_recv_comp_slot(
+       struct netvsc_device *nvdev, struct vmbus_channel *channel, u16 q_idx)
+{
+       u32 filled, avail, next;
+       struct recv_comp_data *rcd;
+
+       if (!nvdev->recv_section)
+               return NULL;
+
+       if (!nvdev->mrc[q_idx].buf)
+               return NULL;
+
+       if (atomic_read(&nvdev->num_outstanding_recvs) >
+           nvdev->recv_section->num_sub_allocs * NETVSC_RCD_WATERMARK / 100)
+               netvsc_chk_recv_comp(nvdev, channel, q_idx);
+
+       count_recv_comp_slot(nvdev, q_idx, &filled, &avail);
+       if (!avail)
+               return NULL;
+
+       next = nvdev->mrc[q_idx].next;
+       rcd = nvdev->mrc[q_idx].buf + next * sizeof(struct recv_comp_data);
+       nvdev->mrc[q_idx].next = (next + 1) % NETVSC_RECVSLOT_MAX;
+
+       atomic_inc(&nvdev->num_outstanding_recvs);
+
+       return rcd;
+}
+
 static void netvsc_receive(struct netvsc_device *net_device,
                        struct vmbus_channel *channel,
                        struct hv_device *device,
@@ -1025,6 +1111,9 @@ static void netvsc_receive(struct netvsc_device *net_device,
        int count = 0;
        struct net_device *ndev = hv_get_drvdata(device);
        void *data;
+       int ret;
+       struct recv_comp_data *rcd;
+       u16 q_idx = channel->offermsg.offer.sub_channel_index;
 
        /*
         * All inbound packets other than send completion should be xfer page
@@ -1069,13 +1158,29 @@ static void netvsc_receive(struct netvsc_device *net_device,
                /* Pass it to the upper layer */
                status = rndis_filter_receive(device, netvsc_packet, &data,
                                              channel);
+       }
 
+       if (!net_device->mrc[q_idx].buf) {
+               ret = netvsc_send_recv_completion(channel,
+                                                 vmxferpage_packet->d.trans_id,
+                                                 status);
+               if (ret)
+                       netdev_err(ndev, "Recv_comp q:%hd, tid:%llx, err:%d\n",
+                                  q_idx, vmxferpage_packet->d.trans_id, ret);
+               return;
        }
 
-       netvsc_send_recv_completion(device, channel, net_device,
-                                   vmxferpage_packet->d.trans_id, status);
-}
+       rcd = get_recv_comp_slot(net_device, channel, q_idx);
 
+       if (!rcd) {
+               netdev_err(ndev, "Recv_comp full buf q:%hd, tid:%llx\n",
+                          q_idx, vmxferpage_packet->d.trans_id);
+               return;
+       }
+
+       rcd->tid = vmxferpage_packet->d.trans_id;
+       rcd->status = status;
+}
 
 static void netvsc_send_table(struct hv_device *hdev,
                              struct nvsp_message *nvmsg)
@@ -1157,11 +1262,11 @@ static void netvsc_process_raw_pkt(struct hv_device *device,
        }
 }
 
-
 void netvsc_channel_cb(void *context)
 {
        int ret;
        struct vmbus_channel *channel = (struct vmbus_channel *)context;
+       u16 q_idx = channel->offermsg.offer.sub_channel_index;
        struct hv_device *device;
        struct netvsc_device *net_device;
        u32 bytes_recvd;
@@ -1213,8 +1318,6 @@ void netvsc_channel_cb(void *context)
                                                       ndev,
                                                       request_id,
                                                       desc);
-
-
                        } else {
                                /*
                                 * We are done for this pass.
@@ -1241,7 +1344,8 @@ void netvsc_channel_cb(void *context)
 
        if (bufferlen > NETVSC_PACKET_SIZE)
                kfree(buffer);
-       return;
+
+       netvsc_chk_recv_comp(net_device, channel, q_idx);
 }
 
 /*
@@ -1263,9 +1367,6 @@ int netvsc_device_add(struct hv_device *device, void *additional_info)
 
        net_device->ring_size = ring_size;
 
-       /* Initialize the NetVSC channel extension */
-       init_completion(&net_device->channel_init_wait);
-
        set_per_channel_state(device->channel, net_device->cb_buffer);
 
        /* Open the channel */