mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-27 09:26:23 +07:00
Merge branch 'hv_netvsc-less-headroom'
Merge branch 'hv_netvsc-less-headroom' K. Y. Srinivasan says: ==================== hv_netvsc: Eliminate the additional head room In an attempt to avoid having to allocate memory on the send path, the netvsc driver was requesting additional head room so that both rndis header and the netvsc packet (the state that had to persist) could be placed in the skb. Since the amount of head room requested was exceeding the default head room as set in LL_MAX_HEADER, we were forcing a reallocation of skb. With this patch-set, I have reduced the size of the netvsc packet to less than 20 bytes and with this reduction we don't need to ask for any additional headroom. We place the rndis header in the skb head room and we place the netvsc packet in control buffer area in the skb. V2: - Addressed review comments: - Eliminated more fields from netvsc packet structure. V3: - Fixed a typo in patch: hv_netvsc: Don't ask for additional head room in the skb. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
0fe824d365
@ -124,37 +124,22 @@ struct ndis_tcp_ip_checksum_info;
|
||||
/*
|
||||
* Represent netvsc packet which contains 1 RNDIS and 1 ethernet frame
|
||||
* within the RNDIS
|
||||
*
|
||||
* The size of this structure is less than 48 bytes and we can now
|
||||
* place this structure in the skb->cb field.
|
||||
*/
|
||||
struct hv_netvsc_packet {
|
||||
/* Bookkeeping stuff */
|
||||
u32 status;
|
||||
u8 cp_partial; /* partial copy into send buffer */
|
||||
|
||||
bool is_data_pkt;
|
||||
bool xmit_more; /* from skb */
|
||||
bool cp_partial; /* partial copy into send buffer */
|
||||
|
||||
u16 vlan_tci;
|
||||
u8 rmsg_size; /* RNDIS header and PPI size */
|
||||
u8 rmsg_pgcnt; /* page count of RNDIS header and PPI */
|
||||
u8 page_buf_cnt;
|
||||
|
||||
u16 q_idx;
|
||||
struct vmbus_channel *channel;
|
||||
|
||||
u64 send_completion_tid;
|
||||
void *send_completion_ctx;
|
||||
void (*send_completion)(void *context);
|
||||
|
||||
u32 send_buf_index;
|
||||
|
||||
/* This points to the memory after page_buf */
|
||||
struct rndis_message *rndis_msg;
|
||||
|
||||
u32 rmsg_size; /* RNDIS header and PPI size */
|
||||
u32 rmsg_pgcnt; /* page count of RNDIS header and PPI */
|
||||
|
||||
u32 total_data_buflen;
|
||||
/* Points to the send/receive buffer where the ethernet frame is */
|
||||
void *data;
|
||||
u32 page_buf_cnt;
|
||||
struct hv_page_buffer *page_buf;
|
||||
};
|
||||
|
||||
struct netvsc_device_info {
|
||||
@ -187,16 +172,22 @@ struct rndis_device {
|
||||
|
||||
|
||||
/* Interface */
|
||||
struct rndis_message;
|
||||
int netvsc_device_add(struct hv_device *device, void *additional_info);
|
||||
int netvsc_device_remove(struct hv_device *device);
|
||||
int netvsc_send(struct hv_device *device,
|
||||
struct hv_netvsc_packet *packet);
|
||||
struct hv_netvsc_packet *packet,
|
||||
struct rndis_message *rndis_msg,
|
||||
struct hv_page_buffer **page_buffer,
|
||||
struct sk_buff *skb);
|
||||
void netvsc_linkstatus_callback(struct hv_device *device_obj,
|
||||
struct rndis_message *resp);
|
||||
void netvsc_xmit_completion(void *context);
|
||||
int netvsc_recv_callback(struct hv_device *device_obj,
|
||||
struct hv_netvsc_packet *packet,
|
||||
struct ndis_tcp_ip_checksum_info *csum_info);
|
||||
void **data,
|
||||
struct ndis_tcp_ip_checksum_info *csum_info,
|
||||
struct vmbus_channel *channel,
|
||||
u16 vlan_tci);
|
||||
void netvsc_channel_cb(void *context);
|
||||
int rndis_filter_open(struct hv_device *dev);
|
||||
int rndis_filter_close(struct hv_device *dev);
|
||||
@ -204,12 +195,13 @@ int rndis_filter_device_add(struct hv_device *dev,
|
||||
void *additional_info);
|
||||
void rndis_filter_device_remove(struct hv_device *dev);
|
||||
int rndis_filter_receive(struct hv_device *dev,
|
||||
struct hv_netvsc_packet *pkt);
|
||||
struct hv_netvsc_packet *pkt,
|
||||
void **data,
|
||||
struct vmbus_channel *channel);
|
||||
|
||||
int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter);
|
||||
int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac);
|
||||
|
||||
|
||||
#define NVSP_INVALID_PROTOCOL_VERSION ((u32)0xFFFFFFFF)
|
||||
|
||||
#define NVSP_PROTOCOL_VERSION_1 2
|
||||
@ -632,7 +624,6 @@ struct nvsp_message {
|
||||
#define RNDIS_PKT_ALIGN_DEFAULT 8
|
||||
|
||||
struct multi_send_data {
|
||||
spinlock_t lock; /* protect struct multi_send_data */
|
||||
struct hv_netvsc_packet *pkt; /* netvsc pkt pending */
|
||||
u32 count; /* counter of batched packets */
|
||||
};
|
||||
@ -1272,5 +1263,4 @@ struct rndis_message {
|
||||
#define TRANSPORT_INFO_IPV6_TCP ((INFO_IPV6 << 16) | INFO_TCP)
|
||||
#define TRANSPORT_INFO_IPV6_UDP ((INFO_IPV6 << 16) | INFO_UDP)
|
||||
|
||||
|
||||
#endif /* _HYPERV_NET_H */
|
||||
|
@ -38,7 +38,6 @@ static struct netvsc_device *alloc_net_device(struct hv_device *device)
|
||||
{
|
||||
struct netvsc_device *net_device;
|
||||
struct net_device *ndev = hv_get_drvdata(device);
|
||||
int i;
|
||||
|
||||
net_device = kzalloc(sizeof(struct netvsc_device), GFP_KERNEL);
|
||||
if (!net_device)
|
||||
@ -58,9 +57,6 @@ static struct netvsc_device *alloc_net_device(struct hv_device *device)
|
||||
net_device->max_pkt = RNDIS_MAX_PKT_DEFAULT;
|
||||
net_device->pkt_align = RNDIS_PKT_ALIGN_DEFAULT;
|
||||
|
||||
for (i = 0; i < num_online_cpus(); i++)
|
||||
spin_lock_init(&net_device->msd[i].lock);
|
||||
|
||||
hv_set_drvdata(device, net_device);
|
||||
return net_device;
|
||||
}
|
||||
@ -610,6 +606,7 @@ static inline void netvsc_free_send_slot(struct netvsc_device *net_device,
|
||||
}
|
||||
|
||||
static void netvsc_send_completion(struct netvsc_device *net_device,
|
||||
struct vmbus_channel *incoming_channel,
|
||||
struct hv_device *device,
|
||||
struct vmpacket_descriptor *packet)
|
||||
{
|
||||
@ -617,6 +614,7 @@ static void netvsc_send_completion(struct netvsc_device *net_device,
|
||||
struct hv_netvsc_packet *nvsc_packet;
|
||||
struct net_device *ndev;
|
||||
u32 send_index;
|
||||
struct sk_buff *skb;
|
||||
|
||||
ndev = net_device->ndev;
|
||||
|
||||
@ -642,18 +640,17 @@ static void netvsc_send_completion(struct netvsc_device *net_device,
|
||||
int queue_sends;
|
||||
|
||||
/* Get the send context */
|
||||
nvsc_packet = (struct hv_netvsc_packet *)(unsigned long)
|
||||
packet->trans_id;
|
||||
skb = (struct sk_buff *)(unsigned long)packet->trans_id;
|
||||
|
||||
/* Notify the layer above us */
|
||||
if (nvsc_packet) {
|
||||
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 = nvsc_packet->channel;
|
||||
nvsc_packet->send_completion(nvsc_packet->
|
||||
send_completion_ctx);
|
||||
channel = incoming_channel;
|
||||
dev_kfree_skb_any(skb);
|
||||
}
|
||||
|
||||
num_outstanding_sends =
|
||||
@ -705,12 +702,17 @@ static u32 netvsc_get_next_send_section(struct netvsc_device *net_device)
|
||||
static u32 netvsc_copy_to_send_buf(struct netvsc_device *net_device,
|
||||
unsigned int section_index,
|
||||
u32 pend_size,
|
||||
struct hv_netvsc_packet *packet)
|
||||
struct hv_netvsc_packet *packet,
|
||||
struct rndis_message *rndis_msg,
|
||||
struct hv_page_buffer **pb,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
char *start = net_device->send_buf;
|
||||
char *dest = start + (section_index * net_device->send_section_size)
|
||||
+ pend_size;
|
||||
int i;
|
||||
bool is_data_pkt = (skb != NULL) ? true : false;
|
||||
bool xmit_more = (skb != NULL) ? skb->xmit_more : false;
|
||||
u32 msg_size = 0;
|
||||
u32 padding = 0;
|
||||
u32 remain = packet->total_data_buflen % net_device->pkt_align;
|
||||
@ -718,17 +720,17 @@ static u32 netvsc_copy_to_send_buf(struct netvsc_device *net_device,
|
||||
packet->page_buf_cnt;
|
||||
|
||||
/* Add padding */
|
||||
if (packet->is_data_pkt && packet->xmit_more && remain &&
|
||||
if (is_data_pkt && xmit_more && remain &&
|
||||
!packet->cp_partial) {
|
||||
padding = net_device->pkt_align - remain;
|
||||
packet->rndis_msg->msg_len += padding;
|
||||
rndis_msg->msg_len += padding;
|
||||
packet->total_data_buflen += padding;
|
||||
}
|
||||
|
||||
for (i = 0; i < page_count; i++) {
|
||||
char *src = phys_to_virt(packet->page_buf[i].pfn << PAGE_SHIFT);
|
||||
u32 offset = packet->page_buf[i].offset;
|
||||
u32 len = packet->page_buf[i].len;
|
||||
char *src = phys_to_virt((*pb)[i].pfn << PAGE_SHIFT);
|
||||
u32 offset = (*pb)[i].offset;
|
||||
u32 len = (*pb)[i].len;
|
||||
|
||||
memcpy(dest, (src + offset), len);
|
||||
msg_size += len;
|
||||
@ -745,19 +747,22 @@ static u32 netvsc_copy_to_send_buf(struct netvsc_device *net_device,
|
||||
|
||||
static inline int netvsc_send_pkt(
|
||||
struct hv_netvsc_packet *packet,
|
||||
struct netvsc_device *net_device)
|
||||
struct netvsc_device *net_device,
|
||||
struct hv_page_buffer **pb,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct nvsp_message nvmsg;
|
||||
struct vmbus_channel *out_channel = packet->channel;
|
||||
u16 q_idx = packet->q_idx;
|
||||
struct vmbus_channel *out_channel = net_device->chn_table[q_idx];
|
||||
struct net_device *ndev = net_device->ndev;
|
||||
u64 req_id;
|
||||
int ret;
|
||||
struct hv_page_buffer *pgbuf;
|
||||
u32 ring_avail = hv_ringbuf_avail_percent(&out_channel->outbound);
|
||||
bool xmit_more = (skb != NULL) ? skb->xmit_more : false;
|
||||
|
||||
nvmsg.hdr.msg_type = NVSP_MSG1_TYPE_SEND_RNDIS_PKT;
|
||||
if (packet->is_data_pkt) {
|
||||
if (skb != NULL) {
|
||||
/* 0 is RMC_DATA; */
|
||||
nvmsg.msg.v1_msg.send_rndis_pkt.channel_type = 0;
|
||||
} else {
|
||||
@ -773,10 +778,7 @@ static inline int netvsc_send_pkt(
|
||||
nvmsg.msg.v1_msg.send_rndis_pkt.send_buf_section_size =
|
||||
packet->total_data_buflen;
|
||||
|
||||
if (packet->send_completion)
|
||||
req_id = (ulong)packet;
|
||||
else
|
||||
req_id = 0;
|
||||
req_id = (ulong)skb;
|
||||
|
||||
if (out_channel->rescind)
|
||||
return -ENODEV;
|
||||
@ -789,11 +791,11 @@ static inline int netvsc_send_pkt(
|
||||
* unnecessarily.
|
||||
*/
|
||||
if (ring_avail < (RING_AVAIL_PERCENT_LOWATER + 1))
|
||||
packet->xmit_more = false;
|
||||
xmit_more = false;
|
||||
|
||||
if (packet->page_buf_cnt) {
|
||||
pgbuf = packet->cp_partial ? packet->page_buf +
|
||||
packet->rmsg_pgcnt : packet->page_buf;
|
||||
pgbuf = packet->cp_partial ? (*pb) +
|
||||
packet->rmsg_pgcnt : (*pb);
|
||||
ret = vmbus_sendpacket_pagebuffer_ctl(out_channel,
|
||||
pgbuf,
|
||||
packet->page_buf_cnt,
|
||||
@ -801,14 +803,14 @@ static inline int netvsc_send_pkt(
|
||||
sizeof(struct nvsp_message),
|
||||
req_id,
|
||||
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED,
|
||||
!packet->xmit_more);
|
||||
!xmit_more);
|
||||
} else {
|
||||
ret = vmbus_sendpacket_ctl(out_channel, &nvmsg,
|
||||
sizeof(struct nvsp_message),
|
||||
req_id,
|
||||
VM_PKT_DATA_INBAND,
|
||||
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED,
|
||||
!packet->xmit_more);
|
||||
!xmit_more);
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
@ -840,7 +842,10 @@ static inline int netvsc_send_pkt(
|
||||
}
|
||||
|
||||
int netvsc_send(struct hv_device *device,
|
||||
struct hv_netvsc_packet *packet)
|
||||
struct hv_netvsc_packet *packet,
|
||||
struct rndis_message *rndis_msg,
|
||||
struct hv_page_buffer **pb,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct netvsc_device *net_device;
|
||||
int ret = 0, m_ret = 0;
|
||||
@ -848,33 +853,27 @@ int netvsc_send(struct hv_device *device,
|
||||
u16 q_idx = packet->q_idx;
|
||||
u32 pktlen = packet->total_data_buflen, msd_len = 0;
|
||||
unsigned int section_index = NETVSC_INVALID_INDEX;
|
||||
unsigned long flag;
|
||||
struct multi_send_data *msdp;
|
||||
struct hv_netvsc_packet *msd_send = NULL, *cur_send = NULL;
|
||||
bool try_batch;
|
||||
bool xmit_more = (skb != NULL) ? skb->xmit_more : false;
|
||||
|
||||
net_device = get_outbound_net_device(device);
|
||||
if (!net_device)
|
||||
return -ENODEV;
|
||||
|
||||
out_channel = net_device->chn_table[q_idx];
|
||||
if (!out_channel) {
|
||||
out_channel = device->channel;
|
||||
q_idx = 0;
|
||||
packet->q_idx = 0;
|
||||
}
|
||||
packet->channel = out_channel;
|
||||
|
||||
packet->send_buf_index = NETVSC_INVALID_INDEX;
|
||||
packet->cp_partial = false;
|
||||
|
||||
msdp = &net_device->msd[q_idx];
|
||||
|
||||
/* batch packets in send buffer if possible */
|
||||
spin_lock_irqsave(&msdp->lock, flag);
|
||||
if (msdp->pkt)
|
||||
msd_len = msdp->pkt->total_data_buflen;
|
||||
|
||||
try_batch = packet->is_data_pkt && msd_len > 0 && msdp->count <
|
||||
try_batch = (skb != NULL) && msd_len > 0 && msdp->count <
|
||||
net_device->max_pkt;
|
||||
|
||||
if (try_batch && msd_len + pktlen + net_device->pkt_align <
|
||||
@ -886,7 +885,7 @@ int netvsc_send(struct hv_device *device,
|
||||
section_index = msdp->pkt->send_buf_index;
|
||||
packet->cp_partial = true;
|
||||
|
||||
} else if (packet->is_data_pkt && pktlen + net_device->pkt_align <
|
||||
} else if ((skb != NULL) && pktlen + net_device->pkt_align <
|
||||
net_device->send_section_size) {
|
||||
section_index = netvsc_get_next_send_section(net_device);
|
||||
if (section_index != NETVSC_INVALID_INDEX) {
|
||||
@ -900,7 +899,7 @@ int netvsc_send(struct hv_device *device,
|
||||
if (section_index != NETVSC_INVALID_INDEX) {
|
||||
netvsc_copy_to_send_buf(net_device,
|
||||
section_index, msd_len,
|
||||
packet);
|
||||
packet, rndis_msg, pb, skb);
|
||||
|
||||
packet->send_buf_index = section_index;
|
||||
|
||||
@ -913,9 +912,9 @@ int netvsc_send(struct hv_device *device,
|
||||
}
|
||||
|
||||
if (msdp->pkt)
|
||||
netvsc_xmit_completion(msdp->pkt);
|
||||
dev_kfree_skb_any(skb);
|
||||
|
||||
if (packet->xmit_more && !packet->cp_partial) {
|
||||
if (xmit_more && !packet->cp_partial) {
|
||||
msdp->pkt = packet;
|
||||
msdp->count++;
|
||||
} else {
|
||||
@ -930,20 +929,18 @@ int netvsc_send(struct hv_device *device,
|
||||
cur_send = packet;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&msdp->lock, flag);
|
||||
|
||||
if (msd_send) {
|
||||
m_ret = netvsc_send_pkt(msd_send, net_device);
|
||||
m_ret = netvsc_send_pkt(msd_send, net_device, pb, skb);
|
||||
|
||||
if (m_ret != 0) {
|
||||
netvsc_free_send_slot(net_device,
|
||||
msd_send->send_buf_index);
|
||||
netvsc_xmit_completion(msd_send);
|
||||
dev_kfree_skb_any(skb);
|
||||
}
|
||||
}
|
||||
|
||||
if (cur_send)
|
||||
ret = netvsc_send_pkt(cur_send, net_device);
|
||||
ret = netvsc_send_pkt(cur_send, net_device, pb, skb);
|
||||
|
||||
if (ret != 0 && section_index != NETVSC_INVALID_INDEX)
|
||||
netvsc_free_send_slot(net_device, section_index);
|
||||
@ -1009,6 +1006,7 @@ static void netvsc_receive(struct netvsc_device *net_device,
|
||||
int i;
|
||||
int count = 0;
|
||||
struct net_device *ndev;
|
||||
void *data;
|
||||
|
||||
ndev = net_device->ndev;
|
||||
|
||||
@ -1043,22 +1041,19 @@ static void netvsc_receive(struct netvsc_device *net_device,
|
||||
}
|
||||
|
||||
count = vmxferpage_packet->range_cnt;
|
||||
netvsc_packet->channel = channel;
|
||||
|
||||
/* Each range represents 1 RNDIS pkt that contains 1 ethernet frame */
|
||||
for (i = 0; i < count; i++) {
|
||||
/* Initialize the netvsc packet */
|
||||
netvsc_packet->status = NVSP_STAT_SUCCESS;
|
||||
netvsc_packet->data = (void *)((unsigned long)net_device->
|
||||
data = (void *)((unsigned long)net_device->
|
||||
recv_buf + vmxferpage_packet->ranges[i].byte_offset);
|
||||
netvsc_packet->total_data_buflen =
|
||||
vmxferpage_packet->ranges[i].byte_count;
|
||||
|
||||
/* Pass it to the upper layer */
|
||||
rndis_filter_receive(device, netvsc_packet);
|
||||
status = rndis_filter_receive(device, netvsc_packet, &data,
|
||||
channel);
|
||||
|
||||
if (netvsc_packet->status != NVSP_STAT_SUCCESS)
|
||||
status = NVSP_STAT_FAIL;
|
||||
}
|
||||
|
||||
netvsc_send_recv_completion(device, channel, net_device,
|
||||
@ -1150,6 +1145,7 @@ void netvsc_channel_cb(void *context)
|
||||
switch (desc->type) {
|
||||
case VM_PKT_COMP:
|
||||
netvsc_send_completion(net_device,
|
||||
channel,
|
||||
device, desc);
|
||||
break;
|
||||
|
||||
|
@ -273,19 +273,12 @@ static u16 netvsc_select_queue(struct net_device *ndev, struct sk_buff *skb,
|
||||
skb_set_hash(skb, hash, PKT_HASH_TYPE_L3);
|
||||
}
|
||||
|
||||
if (!nvsc_dev->chn_table[q_idx])
|
||||
q_idx = 0;
|
||||
|
||||
return q_idx;
|
||||
}
|
||||
|
||||
void netvsc_xmit_completion(void *context)
|
||||
{
|
||||
struct hv_netvsc_packet *packet = (struct hv_netvsc_packet *)context;
|
||||
struct sk_buff *skb = (struct sk_buff *)
|
||||
(unsigned long)packet->send_completion_tid;
|
||||
|
||||
if (skb)
|
||||
dev_kfree_skb_any(skb);
|
||||
}
|
||||
|
||||
static u32 fill_pg_buf(struct page *page, u32 offset, u32 len,
|
||||
struct hv_page_buffer *pb)
|
||||
{
|
||||
@ -321,9 +314,10 @@ static u32 fill_pg_buf(struct page *page, u32 offset, u32 len,
|
||||
}
|
||||
|
||||
static u32 init_page_array(void *hdr, u32 len, struct sk_buff *skb,
|
||||
struct hv_netvsc_packet *packet)
|
||||
struct hv_netvsc_packet *packet,
|
||||
struct hv_page_buffer **page_buf)
|
||||
{
|
||||
struct hv_page_buffer *pb = packet->page_buf;
|
||||
struct hv_page_buffer *pb = *page_buf;
|
||||
u32 slots_used = 0;
|
||||
char *data = skb->data;
|
||||
int frags = skb_shinfo(skb)->nr_frags;
|
||||
@ -433,8 +427,8 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
|
||||
u32 net_trans_info;
|
||||
u32 hash;
|
||||
u32 skb_length;
|
||||
u32 pkt_sz;
|
||||
struct hv_page_buffer page_buf[MAX_PAGE_BUFFER_COUNT];
|
||||
struct hv_page_buffer *pb = page_buf;
|
||||
struct netvsc_stats *tx_stats = this_cpu_ptr(net_device_ctx->tx_stats);
|
||||
|
||||
/* We will atmost need two pages to describe the rndis
|
||||
@ -461,42 +455,34 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
|
||||
goto check_size;
|
||||
}
|
||||
|
||||
pkt_sz = sizeof(struct hv_netvsc_packet) + RNDIS_AND_PPI_SIZE;
|
||||
|
||||
ret = skb_cow_head(skb, pkt_sz);
|
||||
/*
|
||||
* Place the rndis header in the skb head room and
|
||||
* the skb->cb will be used for hv_netvsc_packet
|
||||
* structure.
|
||||
*/
|
||||
ret = skb_cow_head(skb, RNDIS_AND_PPI_SIZE);
|
||||
if (ret) {
|
||||
netdev_err(net, "unable to alloc hv_netvsc_packet\n");
|
||||
ret = -ENOMEM;
|
||||
goto drop;
|
||||
}
|
||||
/* Use the headroom for building up the packet */
|
||||
packet = (struct hv_netvsc_packet *)skb->head;
|
||||
/* Use the skb control buffer for building up the packet */
|
||||
BUILD_BUG_ON(sizeof(struct hv_netvsc_packet) >
|
||||
FIELD_SIZEOF(struct sk_buff, cb));
|
||||
packet = (struct hv_netvsc_packet *)skb->cb;
|
||||
|
||||
packet->status = 0;
|
||||
packet->xmit_more = skb->xmit_more;
|
||||
|
||||
packet->vlan_tci = skb->vlan_tci;
|
||||
packet->page_buf = page_buf;
|
||||
|
||||
packet->q_idx = skb_get_queue_mapping(skb);
|
||||
|
||||
packet->is_data_pkt = true;
|
||||
packet->total_data_buflen = skb->len;
|
||||
|
||||
packet->rndis_msg = (struct rndis_message *)((unsigned long)packet +
|
||||
sizeof(struct hv_netvsc_packet));
|
||||
rndis_msg = (struct rndis_message *)skb->head;
|
||||
|
||||
memset(packet->rndis_msg, 0, RNDIS_AND_PPI_SIZE);
|
||||
memset(rndis_msg, 0, RNDIS_AND_PPI_SIZE);
|
||||
|
||||
/* Set the completion routine */
|
||||
packet->send_completion = netvsc_xmit_completion;
|
||||
packet->send_completion_ctx = packet;
|
||||
packet->send_completion_tid = (unsigned long)skb;
|
||||
|
||||
isvlan = packet->vlan_tci & VLAN_TAG_PRESENT;
|
||||
isvlan = skb->vlan_tci & VLAN_TAG_PRESENT;
|
||||
|
||||
/* Add the rndis header */
|
||||
rndis_msg = packet->rndis_msg;
|
||||
rndis_msg->ndis_msg_type = RNDIS_MSG_PACKET;
|
||||
rndis_msg->msg_len = packet->total_data_buflen;
|
||||
rndis_pkt = &rndis_msg->msg.pkt;
|
||||
@ -522,8 +508,8 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
|
||||
IEEE_8021Q_INFO);
|
||||
vlan = (struct ndis_pkt_8021q_info *)((void *)ppi +
|
||||
ppi->ppi_offset);
|
||||
vlan->vlanid = packet->vlan_tci & VLAN_VID_MASK;
|
||||
vlan->pri = (packet->vlan_tci & VLAN_PRIO_MASK) >>
|
||||
vlan->vlanid = skb->vlan_tci & VLAN_VID_MASK;
|
||||
vlan->pri = (skb->vlan_tci & VLAN_PRIO_MASK) >>
|
||||
VLAN_PRIO_SHIFT;
|
||||
}
|
||||
|
||||
@ -618,9 +604,10 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net)
|
||||
rndis_msg->msg_len += rndis_msg_size;
|
||||
packet->total_data_buflen = rndis_msg->msg_len;
|
||||
packet->page_buf_cnt = init_page_array(rndis_msg, rndis_msg_size,
|
||||
skb, packet);
|
||||
skb, packet, &pb);
|
||||
|
||||
ret = netvsc_send(net_device_ctx->device_ctx, packet);
|
||||
ret = netvsc_send(net_device_ctx->device_ctx, packet,
|
||||
rndis_msg, &pb, skb);
|
||||
|
||||
drop:
|
||||
if (ret == 0) {
|
||||
@ -683,7 +670,10 @@ void netvsc_linkstatus_callback(struct hv_device *device_obj,
|
||||
*/
|
||||
int netvsc_recv_callback(struct hv_device *device_obj,
|
||||
struct hv_netvsc_packet *packet,
|
||||
struct ndis_tcp_ip_checksum_info *csum_info)
|
||||
void **data,
|
||||
struct ndis_tcp_ip_checksum_info *csum_info,
|
||||
struct vmbus_channel *channel,
|
||||
u16 vlan_tci)
|
||||
{
|
||||
struct net_device *net;
|
||||
struct net_device_context *net_device_ctx;
|
||||
@ -692,8 +682,7 @@ int netvsc_recv_callback(struct hv_device *device_obj,
|
||||
|
||||
net = ((struct netvsc_device *)hv_get_drvdata(device_obj))->ndev;
|
||||
if (!net || net->reg_state != NETREG_REGISTERED) {
|
||||
packet->status = NVSP_STAT_FAIL;
|
||||
return 0;
|
||||
return NVSP_STAT_FAIL;
|
||||
}
|
||||
net_device_ctx = netdev_priv(net);
|
||||
rx_stats = this_cpu_ptr(net_device_ctx->rx_stats);
|
||||
@ -702,15 +691,14 @@ int netvsc_recv_callback(struct hv_device *device_obj,
|
||||
skb = netdev_alloc_skb_ip_align(net, packet->total_data_buflen);
|
||||
if (unlikely(!skb)) {
|
||||
++net->stats.rx_dropped;
|
||||
packet->status = NVSP_STAT_FAIL;
|
||||
return 0;
|
||||
return NVSP_STAT_FAIL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy to skb. This copy is needed here since the memory pointed by
|
||||
* hv_netvsc_packet cannot be deallocated
|
||||
*/
|
||||
memcpy(skb_put(skb, packet->total_data_buflen), packet->data,
|
||||
memcpy(skb_put(skb, packet->total_data_buflen), *data,
|
||||
packet->total_data_buflen);
|
||||
|
||||
skb->protocol = eth_type_trans(skb, net);
|
||||
@ -725,11 +713,11 @@ int netvsc_recv_callback(struct hv_device *device_obj,
|
||||
skb->ip_summed = CHECKSUM_NONE;
|
||||
}
|
||||
|
||||
if (packet->vlan_tci & VLAN_TAG_PRESENT)
|
||||
if (vlan_tci & VLAN_TAG_PRESENT)
|
||||
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q),
|
||||
packet->vlan_tci);
|
||||
vlan_tci);
|
||||
|
||||
skb_record_rx_queue(skb, packet->channel->
|
||||
skb_record_rx_queue(skb, channel->
|
||||
offermsg.offer.sub_channel_index);
|
||||
|
||||
u64_stats_update_begin(&rx_stats->syncp);
|
||||
@ -1118,16 +1106,12 @@ static int netvsc_probe(struct hv_device *dev,
|
||||
struct netvsc_device_info device_info;
|
||||
struct netvsc_device *nvdev;
|
||||
int ret;
|
||||
u32 max_needed_headroom;
|
||||
|
||||
net = alloc_etherdev_mq(sizeof(struct net_device_context),
|
||||
num_online_cpus());
|
||||
if (!net)
|
||||
return -ENOMEM;
|
||||
|
||||
max_needed_headroom = sizeof(struct hv_netvsc_packet) +
|
||||
RNDIS_AND_PPI_SIZE;
|
||||
|
||||
netif_carrier_off(net);
|
||||
|
||||
net_device_ctx = netdev_priv(net);
|
||||
@ -1166,13 +1150,6 @@ static int netvsc_probe(struct hv_device *dev,
|
||||
net->ethtool_ops = ðtool_ops;
|
||||
SET_NETDEV_DEV(net, &dev->device);
|
||||
|
||||
/*
|
||||
* Request additional head room in the skb.
|
||||
* We will use this space to build the rndis
|
||||
* heaser and other state we need to maintain.
|
||||
*/
|
||||
net->needed_headroom = max_needed_headroom;
|
||||
|
||||
/* Notify the netvsc driver of the new device */
|
||||
memset(&device_info, 0, sizeof(device_info));
|
||||
device_info.ring_size = ring_size;
|
||||
|
@ -210,37 +210,33 @@ static int rndis_filter_send_request(struct rndis_device *dev,
|
||||
int ret;
|
||||
struct hv_netvsc_packet *packet;
|
||||
struct hv_page_buffer page_buf[2];
|
||||
struct hv_page_buffer *pb = page_buf;
|
||||
|
||||
/* Setup the packet to send it */
|
||||
packet = &req->pkt;
|
||||
|
||||
packet->is_data_pkt = false;
|
||||
packet->total_data_buflen = req->request_msg.msg_len;
|
||||
packet->page_buf_cnt = 1;
|
||||
packet->page_buf = page_buf;
|
||||
|
||||
packet->page_buf[0].pfn = virt_to_phys(&req->request_msg) >>
|
||||
pb[0].pfn = virt_to_phys(&req->request_msg) >>
|
||||
PAGE_SHIFT;
|
||||
packet->page_buf[0].len = req->request_msg.msg_len;
|
||||
packet->page_buf[0].offset =
|
||||
pb[0].len = req->request_msg.msg_len;
|
||||
pb[0].offset =
|
||||
(unsigned long)&req->request_msg & (PAGE_SIZE - 1);
|
||||
|
||||
/* Add one page_buf when request_msg crossing page boundary */
|
||||
if (packet->page_buf[0].offset + packet->page_buf[0].len > PAGE_SIZE) {
|
||||
if (pb[0].offset + pb[0].len > PAGE_SIZE) {
|
||||
packet->page_buf_cnt++;
|
||||
packet->page_buf[0].len = PAGE_SIZE -
|
||||
packet->page_buf[0].offset;
|
||||
packet->page_buf[1].pfn = virt_to_phys((void *)&req->request_msg
|
||||
+ packet->page_buf[0].len) >> PAGE_SHIFT;
|
||||
packet->page_buf[1].offset = 0;
|
||||
packet->page_buf[1].len = req->request_msg.msg_len -
|
||||
packet->page_buf[0].len;
|
||||
pb[0].len = PAGE_SIZE -
|
||||
pb[0].offset;
|
||||
pb[1].pfn = virt_to_phys((void *)&req->request_msg
|
||||
+ pb[0].len) >> PAGE_SHIFT;
|
||||
pb[1].offset = 0;
|
||||
pb[1].len = req->request_msg.msg_len -
|
||||
pb[0].len;
|
||||
}
|
||||
|
||||
packet->send_completion = NULL;
|
||||
packet->xmit_more = false;
|
||||
|
||||
ret = netvsc_send(dev->net_dev->dev, packet);
|
||||
ret = netvsc_send(dev->net_dev->dev, packet, NULL, &pb, NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -348,14 +344,17 @@ static inline void *rndis_get_ppi(struct rndis_packet *rpkt, u32 type)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void rndis_filter_receive_data(struct rndis_device *dev,
|
||||
static int rndis_filter_receive_data(struct rndis_device *dev,
|
||||
struct rndis_message *msg,
|
||||
struct hv_netvsc_packet *pkt)
|
||||
struct hv_netvsc_packet *pkt,
|
||||
void **data,
|
||||
struct vmbus_channel *channel)
|
||||
{
|
||||
struct rndis_packet *rndis_pkt;
|
||||
u32 data_offset;
|
||||
struct ndis_pkt_8021q_info *vlan;
|
||||
struct ndis_tcp_ip_checksum_info *csum_info;
|
||||
u16 vlan_tci = 0;
|
||||
|
||||
rndis_pkt = &msg->msg.pkt;
|
||||
|
||||
@ -373,7 +372,7 @@ static void rndis_filter_receive_data(struct rndis_device *dev,
|
||||
"overflow detected (got %u, min %u)"
|
||||
"...dropping this message!\n",
|
||||
pkt->total_data_buflen, rndis_pkt->data_len);
|
||||
return;
|
||||
return NVSP_STAT_FAIL;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -382,22 +381,23 @@ static void rndis_filter_receive_data(struct rndis_device *dev,
|
||||
* the data packet to the stack, without the rndis trailer padding
|
||||
*/
|
||||
pkt->total_data_buflen = rndis_pkt->data_len;
|
||||
pkt->data = (void *)((unsigned long)pkt->data + data_offset);
|
||||
*data = (void *)((unsigned long)(*data) + data_offset);
|
||||
|
||||
vlan = rndis_get_ppi(rndis_pkt, IEEE_8021Q_INFO);
|
||||
if (vlan) {
|
||||
pkt->vlan_tci = VLAN_TAG_PRESENT | vlan->vlanid |
|
||||
vlan_tci = VLAN_TAG_PRESENT | vlan->vlanid |
|
||||
(vlan->pri << VLAN_PRIO_SHIFT);
|
||||
} else {
|
||||
pkt->vlan_tci = 0;
|
||||
}
|
||||
|
||||
csum_info = rndis_get_ppi(rndis_pkt, TCPIP_CHKSUM_PKTINFO);
|
||||
netvsc_recv_callback(dev->net_dev->dev, pkt, csum_info);
|
||||
return netvsc_recv_callback(dev->net_dev->dev, pkt, data,
|
||||
csum_info, channel, vlan_tci);
|
||||
}
|
||||
|
||||
int rndis_filter_receive(struct hv_device *dev,
|
||||
struct hv_netvsc_packet *pkt)
|
||||
struct hv_netvsc_packet *pkt,
|
||||
void **data,
|
||||
struct vmbus_channel *channel)
|
||||
{
|
||||
struct netvsc_device *net_dev = hv_get_drvdata(dev);
|
||||
struct rndis_device *rndis_dev;
|
||||
@ -406,7 +406,7 @@ int rndis_filter_receive(struct hv_device *dev,
|
||||
int ret = 0;
|
||||
|
||||
if (!net_dev) {
|
||||
ret = -EINVAL;
|
||||
ret = NVSP_STAT_FAIL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
@ -416,7 +416,7 @@ int rndis_filter_receive(struct hv_device *dev,
|
||||
if (!net_dev->extension) {
|
||||
netdev_err(ndev, "got rndis message but no rndis device - "
|
||||
"dropping this message!\n");
|
||||
ret = -ENODEV;
|
||||
ret = NVSP_STAT_FAIL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
@ -424,11 +424,11 @@ int rndis_filter_receive(struct hv_device *dev,
|
||||
if (rndis_dev->state == RNDIS_DEV_UNINITIALIZED) {
|
||||
netdev_err(ndev, "got rndis message but rndis device "
|
||||
"uninitialized...dropping this message!\n");
|
||||
ret = -ENODEV;
|
||||
ret = NVSP_STAT_FAIL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rndis_msg = pkt->data;
|
||||
rndis_msg = *data;
|
||||
|
||||
if (netif_msg_rx_err(net_dev->nd_ctx))
|
||||
dump_rndis_message(dev, rndis_msg);
|
||||
@ -436,7 +436,8 @@ int rndis_filter_receive(struct hv_device *dev,
|
||||
switch (rndis_msg->ndis_msg_type) {
|
||||
case RNDIS_MSG_PACKET:
|
||||
/* data msg */
|
||||
rndis_filter_receive_data(rndis_dev, rndis_msg, pkt);
|
||||
ret = rndis_filter_receive_data(rndis_dev, rndis_msg, pkt,
|
||||
data, channel);
|
||||
break;
|
||||
|
||||
case RNDIS_MSG_INIT_C:
|
||||
@ -459,9 +460,6 @@ int rndis_filter_receive(struct hv_device *dev,
|
||||
}
|
||||
|
||||
exit:
|
||||
if (ret != 0)
|
||||
pkt->status = NVSP_STAT_FAIL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -132,7 +132,9 @@ static inline bool dev_xmit_complete(int rc)
|
||||
* used.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_WLAN) || IS_ENABLED(CONFIG_AX25)
|
||||
#if defined(CONFIG_HYPERV_NET)
|
||||
# define LL_MAX_HEADER 128
|
||||
#elif defined(CONFIG_WLAN) || IS_ENABLED(CONFIG_AX25)
|
||||
# if defined(CONFIG_MAC80211_MESH)
|
||||
# define LL_MAX_HEADER 128
|
||||
# else
|
||||
|
Loading…
Reference in New Issue
Block a user