diff options
author | Olof Johansson <olof@lixom.net> | 2008-03-05 17:34:16 -0500 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2008-03-05 17:34:39 -0500 |
commit | 8d636d8bc5ffcdbf49c72aafcda9ddab7ccb2f41 (patch) | |
tree | 0f441b124752959ba723c87aa471df196f556013 /drivers/net | |
parent | dda56df08a28404004bca313d2a1ba1597acd755 (diff) |
pasemi_mac: jumbo frame support
First cut at jumbo frame support. To support large MTU, one or several
separate channels must be allocated to calculate the TCP/UDP checksum
separately, since the mac lacks enough buffers to hold a whole packet
while it's being calculated.
Furthermore, it seems that a single function channel is not quite
enough to feed one of the 10Gig links, so allocate two channels for
XAUI interfaces.
Signed-off-by: Olof Johansson <olof@lixom.net>
Acked-by: Jeff Garzik <jgarzik@pobox.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/pasemi_mac.c | 294 | ||||
-rw-r--r-- | drivers/net/pasemi_mac.h | 15 |
2 files changed, 275 insertions, 34 deletions
diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 6ea822addde5..54904ad29ea7 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c | |||
@@ -59,11 +59,12 @@ | |||
59 | /* Must be a power of two */ | 59 | /* Must be a power of two */ |
60 | #define RX_RING_SIZE 2048 | 60 | #define RX_RING_SIZE 2048 |
61 | #define TX_RING_SIZE 4096 | 61 | #define TX_RING_SIZE 4096 |
62 | #define CS_RING_SIZE (TX_RING_SIZE*2) | ||
62 | 63 | ||
63 | #define LRO_MAX_AGGR 64 | 64 | #define LRO_MAX_AGGR 64 |
64 | 65 | ||
65 | #define PE_MIN_MTU 64 | 66 | #define PE_MIN_MTU 64 |
66 | #define PE_MAX_MTU 1500 | 67 | #define PE_MAX_MTU 9000 |
67 | #define PE_DEF_MTU ETH_DATA_LEN | 68 | #define PE_DEF_MTU ETH_DATA_LEN |
68 | 69 | ||
69 | #define DEFAULT_MSG_ENABLE \ | 70 | #define DEFAULT_MSG_ENABLE \ |
@@ -81,6 +82,7 @@ | |||
81 | #define RX_DESC(rx, num) ((rx)->chan.ring_virt[(num) & (RX_RING_SIZE-1)]) | 82 | #define RX_DESC(rx, num) ((rx)->chan.ring_virt[(num) & (RX_RING_SIZE-1)]) |
82 | #define RX_DESC_INFO(rx, num) ((rx)->ring_info[(num) & (RX_RING_SIZE-1)]) | 83 | #define RX_DESC_INFO(rx, num) ((rx)->ring_info[(num) & (RX_RING_SIZE-1)]) |
83 | #define RX_BUFF(rx, num) ((rx)->buffers[(num) & (RX_RING_SIZE-1)]) | 84 | #define RX_BUFF(rx, num) ((rx)->buffers[(num) & (RX_RING_SIZE-1)]) |
85 | #define CS_DESC(cs, num) ((cs)->chan.ring_virt[(num) & (CS_RING_SIZE-1)]) | ||
84 | 86 | ||
85 | #define RING_USED(ring) (((ring)->next_to_fill - (ring)->next_to_clean) \ | 87 | #define RING_USED(ring) (((ring)->next_to_fill - (ring)->next_to_clean) \ |
86 | & ((ring)->size - 1)) | 88 | & ((ring)->size - 1)) |
@@ -322,6 +324,103 @@ static int pasemi_mac_unmap_tx_skb(struct pasemi_mac *mac, | |||
322 | return (nfrags + 3) & ~1; | 324 | return (nfrags + 3) & ~1; |
323 | } | 325 | } |
324 | 326 | ||
327 | static struct pasemi_mac_csring *pasemi_mac_setup_csring(struct pasemi_mac *mac) | ||
328 | { | ||
329 | struct pasemi_mac_csring *ring; | ||
330 | u32 val; | ||
331 | unsigned int cfg; | ||
332 | int chno; | ||
333 | |||
334 | ring = pasemi_dma_alloc_chan(TXCHAN, sizeof(struct pasemi_mac_csring), | ||
335 | offsetof(struct pasemi_mac_csring, chan)); | ||
336 | |||
337 | if (!ring) { | ||
338 | dev_err(&mac->pdev->dev, "Can't allocate checksum channel\n"); | ||
339 | goto out_chan; | ||
340 | } | ||
341 | |||
342 | chno = ring->chan.chno; | ||
343 | |||
344 | ring->size = CS_RING_SIZE; | ||
345 | ring->next_to_fill = 0; | ||
346 | |||
347 | /* Allocate descriptors */ | ||
348 | if (pasemi_dma_alloc_ring(&ring->chan, CS_RING_SIZE)) | ||
349 | goto out_ring_desc; | ||
350 | |||
351 | write_dma_reg(PAS_DMA_TXCHAN_BASEL(chno), | ||
352 | PAS_DMA_TXCHAN_BASEL_BRBL(ring->chan.ring_dma)); | ||
353 | val = PAS_DMA_TXCHAN_BASEU_BRBH(ring->chan.ring_dma >> 32); | ||
354 | val |= PAS_DMA_TXCHAN_BASEU_SIZ(CS_RING_SIZE >> 3); | ||
355 | |||
356 | write_dma_reg(PAS_DMA_TXCHAN_BASEU(chno), val); | ||
357 | |||
358 | ring->events[0] = pasemi_dma_alloc_flag(); | ||
359 | ring->events[1] = pasemi_dma_alloc_flag(); | ||
360 | if (ring->events[0] < 0 || ring->events[1] < 0) | ||
361 | goto out_flags; | ||
362 | |||
363 | pasemi_dma_clear_flag(ring->events[0]); | ||
364 | pasemi_dma_clear_flag(ring->events[1]); | ||
365 | |||
366 | ring->fun = pasemi_dma_alloc_fun(); | ||
367 | if (ring->fun < 0) | ||
368 | goto out_fun; | ||
369 | |||
370 | cfg = PAS_DMA_TXCHAN_CFG_TY_FUNC | PAS_DMA_TXCHAN_CFG_UP | | ||
371 | PAS_DMA_TXCHAN_CFG_TATTR(ring->fun) | | ||
372 | PAS_DMA_TXCHAN_CFG_LPSQ | PAS_DMA_TXCHAN_CFG_LPDQ; | ||
373 | |||
374 | if (translation_enabled()) | ||
375 | cfg |= PAS_DMA_TXCHAN_CFG_TRD | PAS_DMA_TXCHAN_CFG_TRR; | ||
376 | |||
377 | write_dma_reg(PAS_DMA_TXCHAN_CFG(chno), cfg); | ||
378 | |||
379 | /* enable channel */ | ||
380 | pasemi_dma_start_chan(&ring->chan, PAS_DMA_TXCHAN_TCMDSTA_SZ | | ||
381 | PAS_DMA_TXCHAN_TCMDSTA_DB | | ||
382 | PAS_DMA_TXCHAN_TCMDSTA_DE | | ||
383 | PAS_DMA_TXCHAN_TCMDSTA_DA); | ||
384 | |||
385 | return ring; | ||
386 | |||
387 | out_fun: | ||
388 | out_flags: | ||
389 | if (ring->events[0] >= 0) | ||
390 | pasemi_dma_free_flag(ring->events[0]); | ||
391 | if (ring->events[1] >= 0) | ||
392 | pasemi_dma_free_flag(ring->events[1]); | ||
393 | pasemi_dma_free_ring(&ring->chan); | ||
394 | out_ring_desc: | ||
395 | pasemi_dma_free_chan(&ring->chan); | ||
396 | out_chan: | ||
397 | |||
398 | return NULL; | ||
399 | } | ||
400 | |||
401 | static void pasemi_mac_setup_csrings(struct pasemi_mac *mac) | ||
402 | { | ||
403 | int i; | ||
404 | mac->cs[0] = pasemi_mac_setup_csring(mac); | ||
405 | if (mac->type == MAC_TYPE_XAUI) | ||
406 | mac->cs[1] = pasemi_mac_setup_csring(mac); | ||
407 | else | ||
408 | mac->cs[1] = 0; | ||
409 | |||
410 | for (i = 0; i < MAX_CS; i++) | ||
411 | if (mac->cs[i]) | ||
412 | mac->num_cs++; | ||
413 | } | ||
414 | |||
415 | static void pasemi_mac_free_csring(struct pasemi_mac_csring *csring) | ||
416 | { | ||
417 | pasemi_dma_stop_chan(&csring->chan); | ||
418 | pasemi_dma_free_flag(csring->events[0]); | ||
419 | pasemi_dma_free_flag(csring->events[1]); | ||
420 | pasemi_dma_free_ring(&csring->chan); | ||
421 | pasemi_dma_free_chan(&csring->chan); | ||
422 | } | ||
423 | |||
325 | static int pasemi_mac_setup_rx_resources(const struct net_device *dev) | 424 | static int pasemi_mac_setup_rx_resources(const struct net_device *dev) |
326 | { | 425 | { |
327 | struct pasemi_mac_rxring *ring; | 426 | struct pasemi_mac_rxring *ring; |
@@ -445,7 +544,7 @@ pasemi_mac_setup_tx_resources(const struct net_device *dev) | |||
445 | cfg = PAS_DMA_TXCHAN_CFG_TY_IFACE | | 544 | cfg = PAS_DMA_TXCHAN_CFG_TY_IFACE | |
446 | PAS_DMA_TXCHAN_CFG_TATTR(mac->dma_if) | | 545 | PAS_DMA_TXCHAN_CFG_TATTR(mac->dma_if) | |
447 | PAS_DMA_TXCHAN_CFG_UP | | 546 | PAS_DMA_TXCHAN_CFG_UP | |
448 | PAS_DMA_TXCHAN_CFG_WT(2); | 547 | PAS_DMA_TXCHAN_CFG_WT(4); |
449 | 548 | ||
450 | if (translation_enabled()) | 549 | if (translation_enabled()) |
451 | cfg |= PAS_DMA_TXCHAN_CFG_TRD | PAS_DMA_TXCHAN_CFG_TRR; | 550 | cfg |= PAS_DMA_TXCHAN_CFG_TRD | PAS_DMA_TXCHAN_CFG_TRR; |
@@ -810,13 +909,21 @@ restart: | |||
810 | u64 mactx = TX_DESC(txring, i); | 909 | u64 mactx = TX_DESC(txring, i); |
811 | struct sk_buff *skb; | 910 | struct sk_buff *skb; |
812 | 911 | ||
813 | skb = TX_DESC_INFO(txring, i+1).skb; | ||
814 | nr_frags = TX_DESC_INFO(txring, i).dma; | ||
815 | |||
816 | if ((mactx & XCT_MACTX_E) || | 912 | if ((mactx & XCT_MACTX_E) || |
817 | (*chan->status & PAS_STATUS_ERROR)) | 913 | (*chan->status & PAS_STATUS_ERROR)) |
818 | pasemi_mac_tx_error(mac, mactx); | 914 | pasemi_mac_tx_error(mac, mactx); |
819 | 915 | ||
916 | /* Skip over control descriptors */ | ||
917 | if (!(mactx & XCT_MACTX_LLEN_M)) { | ||
918 | TX_DESC(txring, i) = 0; | ||
919 | TX_DESC(txring, i+1) = 0; | ||
920 | buf_count = 2; | ||
921 | continue; | ||
922 | } | ||
923 | |||
924 | skb = TX_DESC_INFO(txring, i+1).skb; | ||
925 | nr_frags = TX_DESC_INFO(txring, i).dma; | ||
926 | |||
820 | if (unlikely(mactx & XCT_MACTX_O)) | 927 | if (unlikely(mactx & XCT_MACTX_O)) |
821 | /* Not yet transmitted */ | 928 | /* Not yet transmitted */ |
822 | break; | 929 | break; |
@@ -1058,6 +1165,12 @@ static int pasemi_mac_open(struct net_device *dev) | |||
1058 | if (!mac->tx) | 1165 | if (!mac->tx) |
1059 | goto out_tx_ring; | 1166 | goto out_tx_ring; |
1060 | 1167 | ||
1168 | if (dev->mtu > 1500) { | ||
1169 | pasemi_mac_setup_csrings(mac); | ||
1170 | if (!mac->num_cs) | ||
1171 | goto out_tx_ring; | ||
1172 | } | ||
1173 | |||
1061 | /* 0x3ff with 33MHz clock is about 31us */ | 1174 | /* 0x3ff with 33MHz clock is about 31us */ |
1062 | write_iob_reg(PAS_IOB_DMA_COM_TIMEOUTCFG, | 1175 | write_iob_reg(PAS_IOB_DMA_COM_TIMEOUTCFG, |
1063 | PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0x3ff)); | 1176 | PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0x3ff)); |
@@ -1241,7 +1354,7 @@ static int pasemi_mac_close(struct net_device *dev) | |||
1241 | { | 1354 | { |
1242 | struct pasemi_mac *mac = netdev_priv(dev); | 1355 | struct pasemi_mac *mac = netdev_priv(dev); |
1243 | unsigned int sta; | 1356 | unsigned int sta; |
1244 | int rxch, txch; | 1357 | int rxch, txch, i; |
1245 | 1358 | ||
1246 | rxch = rx_ring(mac)->chan.chno; | 1359 | rxch = rx_ring(mac)->chan.chno; |
1247 | txch = tx_ring(mac)->chan.chno; | 1360 | txch = tx_ring(mac)->chan.chno; |
@@ -1286,6 +1399,9 @@ static int pasemi_mac_close(struct net_device *dev) | |||
1286 | free_irq(mac->tx->chan.irq, mac->tx); | 1399 | free_irq(mac->tx->chan.irq, mac->tx); |
1287 | free_irq(mac->rx->chan.irq, mac->rx); | 1400 | free_irq(mac->rx->chan.irq, mac->rx); |
1288 | 1401 | ||
1402 | for (i = 0; i < mac->num_cs; i++) | ||
1403 | pasemi_mac_free_csring(mac->cs[i]); | ||
1404 | |||
1289 | /* Free resources */ | 1405 | /* Free resources */ |
1290 | pasemi_mac_free_rx_resources(mac); | 1406 | pasemi_mac_free_rx_resources(mac); |
1291 | pasemi_mac_free_tx_resources(mac); | 1407 | pasemi_mac_free_tx_resources(mac); |
@@ -1293,35 +1409,113 @@ static int pasemi_mac_close(struct net_device *dev) | |||
1293 | return 0; | 1409 | return 0; |
1294 | } | 1410 | } |
1295 | 1411 | ||
1412 | static void pasemi_mac_queue_csdesc(const struct sk_buff *skb, | ||
1413 | const dma_addr_t *map, | ||
1414 | const unsigned int *map_size, | ||
1415 | struct pasemi_mac_txring *txring, | ||
1416 | struct pasemi_mac_csring *csring) | ||
1417 | { | ||
1418 | u64 fund; | ||
1419 | dma_addr_t cs_dest; | ||
1420 | const int nh_off = skb_network_offset(skb); | ||
1421 | const int nh_len = skb_network_header_len(skb); | ||
1422 | const int nfrags = skb_shinfo(skb)->nr_frags; | ||
1423 | int cs_size, i, fill, hdr, cpyhdr, evt; | ||
1424 | dma_addr_t csdma; | ||
1425 | |||
1426 | fund = XCT_FUN_ST | XCT_FUN_RR_8BRES | | ||
1427 | XCT_FUN_O | XCT_FUN_FUN(csring->fun) | | ||
1428 | XCT_FUN_CRM_SIG | XCT_FUN_LLEN(skb->len - nh_off) | | ||
1429 | XCT_FUN_SHL(nh_len >> 2) | XCT_FUN_SE; | ||
1430 | |||
1431 | switch (ip_hdr(skb)->protocol) { | ||
1432 | case IPPROTO_TCP: | ||
1433 | fund |= XCT_FUN_SIG_TCP4; | ||
1434 | /* TCP checksum is 16 bytes into the header */ | ||
1435 | cs_dest = map[0] + skb_transport_offset(skb) + 16; | ||
1436 | break; | ||
1437 | case IPPROTO_UDP: | ||
1438 | fund |= XCT_FUN_SIG_UDP4; | ||
1439 | /* UDP checksum is 6 bytes into the header */ | ||
1440 | cs_dest = map[0] + skb_transport_offset(skb) + 6; | ||
1441 | break; | ||
1442 | default: | ||
1443 | BUG(); | ||
1444 | } | ||
1445 | |||
1446 | /* Do the checksum offloaded */ | ||
1447 | fill = csring->next_to_fill; | ||
1448 | hdr = fill; | ||
1449 | |||
1450 | CS_DESC(csring, fill++) = fund; | ||
1451 | /* Room for 8BRES. Checksum result is really 2 bytes into it */ | ||
1452 | csdma = csring->chan.ring_dma + (fill & (CS_RING_SIZE-1)) * 8 + 2; | ||
1453 | CS_DESC(csring, fill++) = 0; | ||
1454 | |||
1455 | CS_DESC(csring, fill) = XCT_PTR_LEN(map_size[0]-nh_off) | XCT_PTR_ADDR(map[0]+nh_off); | ||
1456 | for (i = 1; i <= nfrags; i++) | ||
1457 | CS_DESC(csring, fill+i) = XCT_PTR_LEN(map_size[i]) | XCT_PTR_ADDR(map[i]); | ||
1458 | |||
1459 | fill += i; | ||
1460 | if (fill & 1) | ||
1461 | fill++; | ||
1462 | |||
1463 | /* Copy the result into the TCP packet */ | ||
1464 | cpyhdr = fill; | ||
1465 | CS_DESC(csring, fill++) = XCT_FUN_O | XCT_FUN_FUN(csring->fun) | | ||
1466 | XCT_FUN_LLEN(2) | XCT_FUN_SE; | ||
1467 | CS_DESC(csring, fill++) = XCT_PTR_LEN(2) | XCT_PTR_ADDR(cs_dest) | XCT_PTR_T; | ||
1468 | CS_DESC(csring, fill++) = XCT_PTR_LEN(2) | XCT_PTR_ADDR(csdma); | ||
1469 | fill++; | ||
1470 | |||
1471 | evt = !csring->last_event; | ||
1472 | csring->last_event = evt; | ||
1473 | |||
1474 | /* Event handshaking with MAC TX */ | ||
1475 | CS_DESC(csring, fill++) = CTRL_CMD_T | CTRL_CMD_META_EVT | CTRL_CMD_O | | ||
1476 | CTRL_CMD_ETYPE_SET | CTRL_CMD_REG(csring->events[evt]); | ||
1477 | CS_DESC(csring, fill++) = 0; | ||
1478 | CS_DESC(csring, fill++) = CTRL_CMD_T | CTRL_CMD_META_EVT | CTRL_CMD_O | | ||
1479 | CTRL_CMD_ETYPE_WCLR | CTRL_CMD_REG(csring->events[!evt]); | ||
1480 | CS_DESC(csring, fill++) = 0; | ||
1481 | csring->next_to_fill = fill & (CS_RING_SIZE-1); | ||
1482 | |||
1483 | cs_size = fill - hdr; | ||
1484 | write_dma_reg(PAS_DMA_TXCHAN_INCR(csring->chan.chno), (cs_size) >> 1); | ||
1485 | |||
1486 | /* TX-side event handshaking */ | ||
1487 | fill = txring->next_to_fill; | ||
1488 | TX_DESC(txring, fill++) = CTRL_CMD_T | CTRL_CMD_META_EVT | CTRL_CMD_O | | ||
1489 | CTRL_CMD_ETYPE_WSET | CTRL_CMD_REG(csring->events[evt]); | ||
1490 | TX_DESC(txring, fill++) = 0; | ||
1491 | TX_DESC(txring, fill++) = CTRL_CMD_T | CTRL_CMD_META_EVT | CTRL_CMD_O | | ||
1492 | CTRL_CMD_ETYPE_CLR | CTRL_CMD_REG(csring->events[!evt]); | ||
1493 | TX_DESC(txring, fill++) = 0; | ||
1494 | txring->next_to_fill = fill; | ||
1495 | |||
1496 | write_dma_reg(PAS_DMA_TXCHAN_INCR(txring->chan.chno), 2); | ||
1497 | |||
1498 | return; | ||
1499 | } | ||
1500 | |||
1296 | static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) | 1501 | static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) |
1297 | { | 1502 | { |
1298 | struct pasemi_mac *mac = netdev_priv(dev); | 1503 | struct pasemi_mac * const mac = netdev_priv(dev); |
1299 | struct pasemi_mac_txring *txring; | 1504 | struct pasemi_mac_txring * const txring = tx_ring(mac); |
1300 | u64 dflags, mactx; | 1505 | struct pasemi_mac_csring *csring; |
1506 | u64 dflags = 0; | ||
1507 | u64 mactx; | ||
1301 | dma_addr_t map[MAX_SKB_FRAGS+1]; | 1508 | dma_addr_t map[MAX_SKB_FRAGS+1]; |
1302 | unsigned int map_size[MAX_SKB_FRAGS+1]; | 1509 | unsigned int map_size[MAX_SKB_FRAGS+1]; |
1303 | unsigned long flags; | 1510 | unsigned long flags; |
1304 | int i, nfrags; | 1511 | int i, nfrags; |
1305 | int fill; | 1512 | int fill; |
1513 | const int nh_off = skb_network_offset(skb); | ||
1514 | const int nh_len = skb_network_header_len(skb); | ||
1306 | 1515 | ||
1307 | dflags = XCT_MACTX_O | XCT_MACTX_ST | XCT_MACTX_CRC_PAD; | 1516 | prefetch(&txring->ring_info); |
1308 | |||
1309 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | ||
1310 | const unsigned char *nh = skb_network_header(skb); | ||
1311 | 1517 | ||
1312 | switch (ip_hdr(skb)->protocol) { | 1518 | dflags = XCT_MACTX_O | XCT_MACTX_ST | XCT_MACTX_CRC_PAD; |
1313 | case IPPROTO_TCP: | ||
1314 | dflags |= XCT_MACTX_CSUM_TCP; | ||
1315 | dflags |= XCT_MACTX_IPH(skb_network_header_len(skb) >> 2); | ||
1316 | dflags |= XCT_MACTX_IPO(nh - skb->data); | ||
1317 | break; | ||
1318 | case IPPROTO_UDP: | ||
1319 | dflags |= XCT_MACTX_CSUM_UDP; | ||
1320 | dflags |= XCT_MACTX_IPH(skb_network_header_len(skb) >> 2); | ||
1321 | dflags |= XCT_MACTX_IPO(nh - skb->data); | ||
1322 | break; | ||
1323 | } | ||
1324 | } | ||
1325 | 1519 | ||
1326 | nfrags = skb_shinfo(skb)->nr_frags; | 1520 | nfrags = skb_shinfo(skb)->nr_frags; |
1327 | 1521 | ||
@@ -1344,24 +1538,46 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) | |||
1344 | } | 1538 | } |
1345 | } | 1539 | } |
1346 | 1540 | ||
1347 | mactx = dflags | XCT_MACTX_LLEN(skb->len); | 1541 | if (skb->ip_summed == CHECKSUM_PARTIAL && skb->len <= 1540) { |
1542 | switch (ip_hdr(skb)->protocol) { | ||
1543 | case IPPROTO_TCP: | ||
1544 | dflags |= XCT_MACTX_CSUM_TCP; | ||
1545 | dflags |= XCT_MACTX_IPH(nh_len >> 2); | ||
1546 | dflags |= XCT_MACTX_IPO(nh_off); | ||
1547 | break; | ||
1548 | case IPPROTO_UDP: | ||
1549 | dflags |= XCT_MACTX_CSUM_UDP; | ||
1550 | dflags |= XCT_MACTX_IPH(nh_len >> 2); | ||
1551 | dflags |= XCT_MACTX_IPO(nh_off); | ||
1552 | break; | ||
1553 | default: | ||
1554 | WARN_ON(1); | ||
1555 | } | ||
1556 | } | ||
1348 | 1557 | ||
1349 | txring = tx_ring(mac); | 1558 | mactx = dflags | XCT_MACTX_LLEN(skb->len); |
1350 | 1559 | ||
1351 | spin_lock_irqsave(&txring->lock, flags); | 1560 | spin_lock_irqsave(&txring->lock, flags); |
1352 | 1561 | ||
1353 | fill = txring->next_to_fill; | ||
1354 | |||
1355 | /* Avoid stepping on the same cache line that the DMA controller | 1562 | /* Avoid stepping on the same cache line that the DMA controller |
1356 | * is currently about to send, so leave at least 8 words available. | 1563 | * is currently about to send, so leave at least 8 words available. |
1357 | * Total free space needed is mactx + fragments + 8 | 1564 | * Total free space needed is mactx + fragments + 8 |
1358 | */ | 1565 | */ |
1359 | if (RING_AVAIL(txring) < nfrags + 10) { | 1566 | if (RING_AVAIL(txring) < nfrags + 14) { |
1360 | /* no room -- stop the queue and wait for tx intr */ | 1567 | /* no room -- stop the queue and wait for tx intr */ |
1361 | netif_stop_queue(dev); | 1568 | netif_stop_queue(dev); |
1362 | goto out_err; | 1569 | goto out_err; |
1363 | } | 1570 | } |
1364 | 1571 | ||
1572 | /* Queue up checksum + event descriptors, if needed */ | ||
1573 | if (mac->num_cs && skb->ip_summed == CHECKSUM_PARTIAL && skb->len > 1540) { | ||
1574 | csring = mac->cs[mac->last_cs]; | ||
1575 | mac->last_cs = (mac->last_cs + 1) % mac->num_cs; | ||
1576 | |||
1577 | pasemi_mac_queue_csdesc(skb, map, map_size, txring, csring); | ||
1578 | } | ||
1579 | |||
1580 | fill = txring->next_to_fill; | ||
1365 | TX_DESC(txring, fill) = mactx; | 1581 | TX_DESC(txring, fill) = mactx; |
1366 | TX_DESC_INFO(txring, fill).dma = nfrags; | 1582 | TX_DESC_INFO(txring, fill).dma = nfrags; |
1367 | fill++; | 1583 | fill++; |
@@ -1439,8 +1655,9 @@ static int pasemi_mac_change_mtu(struct net_device *dev, int new_mtu) | |||
1439 | { | 1655 | { |
1440 | struct pasemi_mac *mac = netdev_priv(dev); | 1656 | struct pasemi_mac *mac = netdev_priv(dev); |
1441 | unsigned int reg; | 1657 | unsigned int reg; |
1442 | unsigned int rcmdsta; | 1658 | unsigned int rcmdsta = 0; |
1443 | int running; | 1659 | int running; |
1660 | int ret = 0; | ||
1444 | 1661 | ||
1445 | if (new_mtu < PE_MIN_MTU || new_mtu > PE_MAX_MTU) | 1662 | if (new_mtu < PE_MIN_MTU || new_mtu > PE_MAX_MTU) |
1446 | return -EINVAL; | 1663 | return -EINVAL; |
@@ -1462,6 +1679,16 @@ static int pasemi_mac_change_mtu(struct net_device *dev, int new_mtu) | |||
1462 | pasemi_mac_pause_rxint(mac); | 1679 | pasemi_mac_pause_rxint(mac); |
1463 | pasemi_mac_clean_rx(rx_ring(mac), RX_RING_SIZE); | 1680 | pasemi_mac_clean_rx(rx_ring(mac), RX_RING_SIZE); |
1464 | pasemi_mac_free_rx_buffers(mac); | 1681 | pasemi_mac_free_rx_buffers(mac); |
1682 | |||
1683 | } | ||
1684 | |||
1685 | /* Setup checksum channels if large MTU and none already allocated */ | ||
1686 | if (new_mtu > 1500 && !mac->num_cs) { | ||
1687 | pasemi_mac_setup_csrings(mac); | ||
1688 | if (!mac->num_cs) { | ||
1689 | ret = -ENOMEM; | ||
1690 | goto out; | ||
1691 | } | ||
1465 | } | 1692 | } |
1466 | 1693 | ||
1467 | /* Change maxf, i.e. what size frames are accepted. | 1694 | /* Change maxf, i.e. what size frames are accepted. |
@@ -1476,6 +1703,7 @@ static int pasemi_mac_change_mtu(struct net_device *dev, int new_mtu) | |||
1476 | /* MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */ | 1703 | /* MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */ |
1477 | mac->bufsz = new_mtu + ETH_HLEN + ETH_FCS_LEN + LOCAL_SKB_ALIGN + 128; | 1704 | mac->bufsz = new_mtu + ETH_HLEN + ETH_FCS_LEN + LOCAL_SKB_ALIGN + 128; |
1478 | 1705 | ||
1706 | out: | ||
1479 | if (running) { | 1707 | if (running) { |
1480 | write_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if), | 1708 | write_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if), |
1481 | rcmdsta | PAS_DMA_RXINT_RCMDSTA_EN); | 1709 | rcmdsta | PAS_DMA_RXINT_RCMDSTA_EN); |
@@ -1488,7 +1716,7 @@ static int pasemi_mac_change_mtu(struct net_device *dev, int new_mtu) | |||
1488 | pasemi_mac_intf_enable(mac); | 1716 | pasemi_mac_intf_enable(mac); |
1489 | } | 1717 | } |
1490 | 1718 | ||
1491 | return 0; | 1719 | return ret; |
1492 | } | 1720 | } |
1493 | 1721 | ||
1494 | static int __devinit | 1722 | static int __devinit |
diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h index 99e7b9329a6f..90c51670a1e7 100644 --- a/drivers/net/pasemi_mac.h +++ b/drivers/net/pasemi_mac.h | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/phy.h> | 27 | #include <linux/phy.h> |
28 | 28 | ||
29 | #define MAX_LRO_DESCRIPTORS 8 | 29 | #define MAX_LRO_DESCRIPTORS 8 |
30 | #define MAX_CS 2 | ||
30 | 31 | ||
31 | struct pasemi_mac_txring { | 32 | struct pasemi_mac_txring { |
32 | struct pasemi_dmachan chan; /* Must be first */ | 33 | struct pasemi_dmachan chan; /* Must be first */ |
@@ -51,6 +52,15 @@ struct pasemi_mac_rxring { | |||
51 | struct pasemi_mac *mac; /* Needed in intr handler */ | 52 | struct pasemi_mac *mac; /* Needed in intr handler */ |
52 | }; | 53 | }; |
53 | 54 | ||
55 | struct pasemi_mac_csring { | ||
56 | struct pasemi_dmachan chan; | ||
57 | unsigned int size; | ||
58 | unsigned int next_to_fill; | ||
59 | int events[2]; | ||
60 | int last_event; | ||
61 | int fun; | ||
62 | }; | ||
63 | |||
54 | struct pasemi_mac { | 64 | struct pasemi_mac { |
55 | struct net_device *netdev; | 65 | struct net_device *netdev; |
56 | struct pci_dev *pdev; | 66 | struct pci_dev *pdev; |
@@ -60,10 +70,12 @@ struct pasemi_mac { | |||
60 | struct napi_struct napi; | 70 | struct napi_struct napi; |
61 | 71 | ||
62 | int bufsz; /* RX ring buffer size */ | 72 | int bufsz; /* RX ring buffer size */ |
73 | int last_cs; | ||
74 | int num_cs; | ||
75 | u32 dma_if; | ||
63 | u8 type; | 76 | u8 type; |
64 | #define MAC_TYPE_GMAC 1 | 77 | #define MAC_TYPE_GMAC 1 |
65 | #define MAC_TYPE_XAUI 2 | 78 | #define MAC_TYPE_XAUI 2 |
66 | u32 dma_if; | ||
67 | 79 | ||
68 | u8 mac_addr[6]; | 80 | u8 mac_addr[6]; |
69 | 81 | ||
@@ -74,6 +86,7 @@ struct pasemi_mac { | |||
74 | 86 | ||
75 | struct pasemi_mac_txring *tx; | 87 | struct pasemi_mac_txring *tx; |
76 | struct pasemi_mac_rxring *rx; | 88 | struct pasemi_mac_rxring *rx; |
89 | struct pasemi_mac_csring *cs[MAX_CS]; | ||
77 | char tx_irq_name[10]; /* "eth%d tx" */ | 90 | char tx_irq_name[10]; /* "eth%d tx" */ |
78 | char rx_irq_name[10]; /* "eth%d rx" */ | 91 | char rx_irq_name[10]; /* "eth%d rx" */ |
79 | int link; | 92 | int link; |