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 | |
| 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')
| -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; |
