|
@@ -696,69 +696,78 @@ static inline void netvsc_free_send_slot(struct netvsc_device *net_device,
|
|
sync_change_bit(index, net_device->send_section_map);
|
|
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_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]);
|
|
|
|
+
|
|
|
|
+ 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,
|
|
static void netvsc_send_completion(struct netvsc_device *net_device,
|
|
struct vmbus_channel *incoming_channel,
|
|
struct vmbus_channel *incoming_channel,
|
|
struct hv_device *device,
|
|
struct hv_device *device,
|
|
struct vmpacket_descriptor *packet)
|
|
struct vmpacket_descriptor *packet)
|
|
{
|
|
{
|
|
struct nvsp_message *nvsp_packet;
|
|
struct nvsp_message *nvsp_packet;
|
|
- struct hv_netvsc_packet *nvsc_packet;
|
|
|
|
struct net_device *ndev = hv_get_drvdata(device);
|
|
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 +
|
|
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 */
|
|
/* Copy the response back */
|
|
memcpy(&net_device->channel_init_pkt, nvsp_packet,
|
|
memcpy(&net_device->channel_init_pkt, nvsp_packet,
|
|
sizeof(struct nvsp_message));
|
|
sizeof(struct nvsp_message));
|
|
complete(&net_device->channel_init_wait);
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|