aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/netxen
diff options
context:
space:
mode:
authorDhananjay Phadke <dhananjay@netxen.com>2009-08-05 03:34:09 -0400
committerDavid S. Miller <davem@davemloft.net>2009-08-05 15:40:15 -0400
commitc1c00ab8626298ac784ea344bf10e94b5bd9bcb5 (patch)
tree49c6479ddaa4121b06cc762f1ee1e19fdfde3e65 /drivers/net/netxen
parent06db58c0cd92e157a4ccf2b6836c9f4b931c7cda (diff)
netxen: add hardware LRO support
Add support to handle aggregate packets from firmware. Local TCP flows are automatically identified by firmware based on the dest IP hash added by driver for local IP addresses. The packets are sent down on the jumbo rx ring. Signed-off-by: Narender Kumar <narender.kumar@qlogic.com> Signed-off-by: Dhananjay Phadke <dhananjay@netxen.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/netxen')
-rw-r--r--drivers/net/netxen/netxen_nic.h21
-rw-r--r--drivers/net/netxen/netxen_nic_ctx.c2
-rw-r--r--drivers/net/netxen/netxen_nic_init.c124
3 files changed, 125 insertions, 22 deletions
diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h
index bb4aa4f58676..ae81f7022d23 100644
--- a/drivers/net/netxen/netxen_nic.h
+++ b/drivers/net/netxen/netxen_nic.h
@@ -365,6 +365,7 @@ struct rcv_desc {
365#define NETXEN_NIC_RXPKT_DESC 0x04 365#define NETXEN_NIC_RXPKT_DESC 0x04
366#define NETXEN_OLD_RXPKT_DESC 0x3f 366#define NETXEN_OLD_RXPKT_DESC 0x3f
367#define NETXEN_NIC_RESPONSE_DESC 0x05 367#define NETXEN_NIC_RESPONSE_DESC 0x05
368#define NETXEN_NIC_LRO_DESC 0x12
368 369
369/* for status field in status_desc */ 370/* for status field in status_desc */
370#define STATUS_NEED_CKSUM (1) 371#define STATUS_NEED_CKSUM (1)
@@ -398,6 +399,24 @@ struct rcv_desc {
398#define netxen_get_sts_opcode(sts_data) \ 399#define netxen_get_sts_opcode(sts_data) \
399 (((sts_data) >> 58) & 0x03F) 400 (((sts_data) >> 58) & 0x03F)
400 401
402#define netxen_get_lro_sts_refhandle(sts_data) \
403 ((sts_data) & 0x0FFFF)
404#define netxen_get_lro_sts_length(sts_data) \
405 (((sts_data) >> 16) & 0x0FFFF)
406#define netxen_get_lro_sts_l2_hdr_offset(sts_data) \
407 (((sts_data) >> 32) & 0x0FF)
408#define netxen_get_lro_sts_l4_hdr_offset(sts_data) \
409 (((sts_data) >> 40) & 0x0FF)
410#define netxen_get_lro_sts_timestamp(sts_data) \
411 (((sts_data) >> 48) & 0x1)
412#define netxen_get_lro_sts_type(sts_data) \
413 (((sts_data) >> 49) & 0x7)
414#define netxen_get_lro_sts_push_flag(sts_data) \
415 (((sts_data) >> 52) & 0x1)
416#define netxen_get_lro_sts_seq_number(sts_data) \
417 ((sts_data) & 0x0FFFFFFFF)
418
419
401struct status_desc { 420struct status_desc {
402 __le64 status_desc_data[2]; 421 __le64 status_desc_data[2];
403} __attribute__ ((aligned(16))); 422} __attribute__ ((aligned(16)));
@@ -712,6 +731,7 @@ struct netxen_recv_context {
712#define NX_CAP0_LSO NX_CAP_BIT(0, 6) 731#define NX_CAP0_LSO NX_CAP_BIT(0, 6)
713#define NX_CAP0_JUMBO_CONTIGUOUS NX_CAP_BIT(0, 7) 732#define NX_CAP0_JUMBO_CONTIGUOUS NX_CAP_BIT(0, 7)
714#define NX_CAP0_LRO_CONTIGUOUS NX_CAP_BIT(0, 8) 733#define NX_CAP0_LRO_CONTIGUOUS NX_CAP_BIT(0, 8)
734#define NX_CAP0_HW_LRO NX_CAP_BIT(0, 10)
715 735
716/* 736/*
717 * Context state 737 * Context state
@@ -969,6 +989,7 @@ typedef struct {
969#define NX_FW_CAPABILITY_PEXQ (1 << 7) 989#define NX_FW_CAPABILITY_PEXQ (1 << 7)
970#define NX_FW_CAPABILITY_BDG (1 << 8) 990#define NX_FW_CAPABILITY_BDG (1 << 8)
971#define NX_FW_CAPABILITY_FVLANTX (1 << 9) 991#define NX_FW_CAPABILITY_FVLANTX (1 << 9)
992#define NX_FW_CAPABILITY_HW_LRO (1 << 10)
972 993
973/* module types */ 994/* module types */
974#define LINKEVENT_MODULE_NOT_PRESENT 1 995#define LINKEVENT_MODULE_NOT_PRESENT 1
diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c
index 9e0469643d34..412d65829d20 100644
--- a/drivers/net/netxen/netxen_nic_ctx.c
+++ b/drivers/net/netxen/netxen_nic_ctx.c
@@ -203,6 +203,8 @@ nx_fw_cmd_create_rx_ctx(struct netxen_adapter *adapter)
203 203
204 cap = (NX_CAP0_LEGACY_CONTEXT | NX_CAP0_LEGACY_MN); 204 cap = (NX_CAP0_LEGACY_CONTEXT | NX_CAP0_LEGACY_MN);
205 cap |= (NX_CAP0_JUMBO_CONTIGUOUS | NX_CAP0_LRO_CONTIGUOUS); 205 cap |= (NX_CAP0_JUMBO_CONTIGUOUS | NX_CAP0_LRO_CONTIGUOUS);
206 if (adapter->capabilities & NX_FW_CAPABILITY_HW_LRO)
207 cap |= NX_CAP0_HW_LRO;
206 208
207 prq->capabilities[0] = cpu_to_le32(cap); 209 prq->capabilities[0] = cpu_to_le32(cap);
208 prq->host_int_crb_mode = 210 prq->host_int_crb_mode =
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c
index 81253abbfa34..582828756ef4 100644
--- a/drivers/net/netxen/netxen_nic_init.c
+++ b/drivers/net/netxen/netxen_nic_init.c
@@ -1242,20 +1242,31 @@ no_skb:
1242 1242
1243static struct netxen_rx_buffer * 1243static struct netxen_rx_buffer *
1244netxen_process_rcv(struct netxen_adapter *adapter, 1244netxen_process_rcv(struct netxen_adapter *adapter,
1245 int ring, int index, int length, int cksum, int pkt_offset, 1245 struct nx_host_sds_ring *sds_ring,
1246 struct nx_host_sds_ring *sds_ring) 1246 int ring, u64 sts_data0)
1247{ 1247{
1248 struct net_device *netdev = adapter->netdev; 1248 struct net_device *netdev = adapter->netdev;
1249 struct netxen_recv_context *recv_ctx = &adapter->recv_ctx; 1249 struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
1250 struct netxen_rx_buffer *buffer; 1250 struct netxen_rx_buffer *buffer;
1251 struct sk_buff *skb; 1251 struct sk_buff *skb;
1252 struct nx_host_rds_ring *rds_ring = &recv_ctx->rds_rings[ring]; 1252 struct nx_host_rds_ring *rds_ring;
1253 int index, length, cksum, pkt_offset;
1253 1254
1254 if (unlikely(index > rds_ring->num_desc)) 1255 if (unlikely(ring >= adapter->max_rds_rings))
1256 return NULL;
1257
1258 rds_ring = &recv_ctx->rds_rings[ring];
1259
1260 index = netxen_get_sts_refhandle(sts_data0);
1261 if (unlikely(index >= rds_ring->num_desc))
1255 return NULL; 1262 return NULL;
1256 1263
1257 buffer = &rds_ring->rx_buf_arr[index]; 1264 buffer = &rds_ring->rx_buf_arr[index];
1258 1265
1266 length = netxen_get_sts_totallength(sts_data0);
1267 cksum = netxen_get_sts_status(sts_data0);
1268 pkt_offset = netxen_get_sts_pkt_offset(sts_data0);
1269
1259 skb = netxen_process_rxbuf(adapter, rds_ring, index, cksum); 1270 skb = netxen_process_rxbuf(adapter, rds_ring, index, cksum);
1260 if (!skb) 1271 if (!skb)
1261 return buffer; 1272 return buffer;
@@ -1279,6 +1290,78 @@ netxen_process_rcv(struct netxen_adapter *adapter,
1279 return buffer; 1290 return buffer;
1280} 1291}
1281 1292
1293#define TCP_HDR_SIZE 20
1294#define TCP_TS_OPTION_SIZE 12
1295#define TCP_TS_HDR_SIZE (TCP_HDR_SIZE + TCP_TS_OPTION_SIZE)
1296
1297static struct netxen_rx_buffer *
1298netxen_process_lro(struct netxen_adapter *adapter,
1299 struct nx_host_sds_ring *sds_ring,
1300 int ring, u64 sts_data0, u64 sts_data1)
1301{
1302 struct net_device *netdev = adapter->netdev;
1303 struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
1304 struct netxen_rx_buffer *buffer;
1305 struct sk_buff *skb;
1306 struct nx_host_rds_ring *rds_ring;
1307 struct iphdr *iph;
1308 struct tcphdr *th;
1309 bool push, timestamp;
1310 int l2_hdr_offset, l4_hdr_offset;
1311 int index;
1312 u16 lro_length, length, data_offset;
1313 u32 seq_number;
1314
1315 if (unlikely(ring > adapter->max_rds_rings))
1316 return NULL;
1317
1318 rds_ring = &recv_ctx->rds_rings[ring];
1319
1320 index = netxen_get_lro_sts_refhandle(sts_data0);
1321 if (unlikely(index > rds_ring->num_desc))
1322 return NULL;
1323
1324 buffer = &rds_ring->rx_buf_arr[index];
1325
1326 timestamp = netxen_get_lro_sts_timestamp(sts_data0);
1327 lro_length = netxen_get_lro_sts_length(sts_data0);
1328 l2_hdr_offset = netxen_get_lro_sts_l2_hdr_offset(sts_data0);
1329 l4_hdr_offset = netxen_get_lro_sts_l4_hdr_offset(sts_data0);
1330 push = netxen_get_lro_sts_push_flag(sts_data0);
1331 seq_number = netxen_get_lro_sts_seq_number(sts_data1);
1332
1333 skb = netxen_process_rxbuf(adapter, rds_ring, index, STATUS_CKSUM_OK);
1334 if (!skb)
1335 return buffer;
1336
1337 if (timestamp)
1338 data_offset = l4_hdr_offset + TCP_TS_HDR_SIZE;
1339 else
1340 data_offset = l4_hdr_offset + TCP_HDR_SIZE;
1341
1342 skb_put(skb, lro_length + data_offset);
1343
1344 skb->truesize = (skb->len + sizeof(struct sk_buff) +
1345 ((unsigned long)skb->data - (unsigned long)skb->head));
1346
1347 skb_pull(skb, l2_hdr_offset);
1348 skb->protocol = eth_type_trans(skb, netdev);
1349
1350 iph = (struct iphdr *)skb->data;
1351 th = (struct tcphdr *)(skb->data + (iph->ihl << 2));
1352
1353 length = (iph->ihl << 2) + (th->doff << 2) + lro_length;
1354 iph->tot_len = htons(length);
1355 iph->check = 0;
1356 iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
1357 th->psh = push;
1358 th->seq = htonl(seq_number);
1359
1360 netif_receive_skb(skb);
1361
1362 return buffer;
1363}
1364
1282#define netxen_merge_rx_buffers(list, head) \ 1365#define netxen_merge_rx_buffers(list, head) \
1283 do { list_splice_tail_init(list, head); } while (0); 1366 do { list_splice_tail_init(list, head); } while (0);
1284 1367
@@ -1295,28 +1378,33 @@ netxen_process_rcv_ring(struct nx_host_sds_ring *sds_ring, int max)
1295 u32 consumer = sds_ring->consumer; 1378 u32 consumer = sds_ring->consumer;
1296 1379
1297 int count = 0; 1380 int count = 0;
1298 u64 sts_data; 1381 u64 sts_data0, sts_data1;
1299 int opcode, ring, index, length, cksum, pkt_offset, desc_cnt; 1382 int opcode, ring = 0, desc_cnt;
1300 1383
1301 while (count < max) { 1384 while (count < max) {
1302 desc = &sds_ring->desc_head[consumer]; 1385 desc = &sds_ring->desc_head[consumer];
1303 sts_data = le64_to_cpu(desc->status_desc_data[0]); 1386 sts_data0 = le64_to_cpu(desc->status_desc_data[0]);
1304 1387
1305 if (!(sts_data & STATUS_OWNER_HOST)) 1388 if (!(sts_data0 & STATUS_OWNER_HOST))
1306 break; 1389 break;
1307 1390
1308 desc_cnt = netxen_get_sts_desc_cnt(sts_data); 1391 desc_cnt = netxen_get_sts_desc_cnt(sts_data0);
1309 ring = netxen_get_sts_type(sts_data);
1310 1392
1311 if (ring > RCV_RING_JUMBO) 1393 opcode = netxen_get_sts_opcode(sts_data0);
1312 goto skip;
1313
1314 opcode = netxen_get_sts_opcode(sts_data);
1315 1394
1316 switch (opcode) { 1395 switch (opcode) {
1317 case NETXEN_NIC_RXPKT_DESC: 1396 case NETXEN_NIC_RXPKT_DESC:
1318 case NETXEN_OLD_RXPKT_DESC: 1397 case NETXEN_OLD_RXPKT_DESC:
1319 case NETXEN_NIC_SYN_OFFLOAD: 1398 case NETXEN_NIC_SYN_OFFLOAD:
1399 ring = netxen_get_sts_type(sts_data0);
1400 rxbuf = netxen_process_rcv(adapter, sds_ring,
1401 ring, sts_data0);
1402 break;
1403 case NETXEN_NIC_LRO_DESC:
1404 ring = netxen_get_lro_sts_type(sts_data0);
1405 sts_data1 = le64_to_cpu(desc->status_desc_data[1]);
1406 rxbuf = netxen_process_lro(adapter, sds_ring,
1407 ring, sts_data0, sts_data1);
1320 break; 1408 break;
1321 case NETXEN_NIC_RESPONSE_DESC: 1409 case NETXEN_NIC_RESPONSE_DESC:
1322 netxen_handle_fw_message(desc_cnt, consumer, sds_ring); 1410 netxen_handle_fw_message(desc_cnt, consumer, sds_ring);
@@ -1326,14 +1414,6 @@ netxen_process_rcv_ring(struct nx_host_sds_ring *sds_ring, int max)
1326 1414
1327 WARN_ON(desc_cnt > 1); 1415 WARN_ON(desc_cnt > 1);
1328 1416
1329 index = netxen_get_sts_refhandle(sts_data);
1330 length = netxen_get_sts_totallength(sts_data);
1331 cksum = netxen_get_sts_status(sts_data);
1332 pkt_offset = netxen_get_sts_pkt_offset(sts_data);
1333
1334 rxbuf = netxen_process_rcv(adapter, ring, index,
1335 length, cksum, pkt_offset, sds_ring);
1336
1337 if (rxbuf) 1417 if (rxbuf)
1338 list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]); 1418 list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]);
1339 1419