diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/Makefile | 3 | ||||
-rw-r--r-- | drivers/net/pasemi_mac.c | 324 | ||||
-rw-r--r-- | drivers/net/pasemi_mac.h | 35 | ||||
-rw-r--r-- | drivers/net/pasemi_mac_ethtool.c | 159 |
4 files changed, 463 insertions, 58 deletions
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 3b1ea321dc05..4b442739e7bf 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile | |||
@@ -218,7 +218,8 @@ obj-$(CONFIG_SMC911X) += smc911x.o | |||
218 | obj-$(CONFIG_BFIN_MAC) += bfin_mac.o | 218 | obj-$(CONFIG_BFIN_MAC) += bfin_mac.o |
219 | obj-$(CONFIG_DM9000) += dm9000.o | 219 | obj-$(CONFIG_DM9000) += dm9000.o |
220 | obj-$(CONFIG_FEC_8XX) += fec_8xx/ | 220 | obj-$(CONFIG_FEC_8XX) += fec_8xx/ |
221 | obj-$(CONFIG_PASEMI_MAC) += pasemi_mac.o | 221 | obj-$(CONFIG_PASEMI_MAC) += pasemi_mac_driver.o |
222 | pasemi_mac_driver-objs := pasemi_mac.o pasemi_mac_ethtool.o | ||
222 | obj-$(CONFIG_MLX4_CORE) += mlx4/ | 223 | obj-$(CONFIG_MLX4_CORE) += mlx4/ |
223 | obj-$(CONFIG_ENC28J60) += enc28j60.o | 224 | obj-$(CONFIG_ENC28J60) += enc28j60.o |
224 | 225 | ||
diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 2e39e0285d8f..c50f0f4de6d8 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c | |||
@@ -55,15 +55,10 @@ | |||
55 | * - Multiqueue RX/TX | 55 | * - Multiqueue RX/TX |
56 | */ | 56 | */ |
57 | 57 | ||
58 | |||
59 | /* Must be a power of two */ | ||
60 | #define RX_RING_SIZE 2048 | ||
61 | #define TX_RING_SIZE 4096 | ||
62 | |||
63 | #define LRO_MAX_AGGR 64 | 58 | #define LRO_MAX_AGGR 64 |
64 | 59 | ||
65 | #define PE_MIN_MTU 64 | 60 | #define PE_MIN_MTU 64 |
66 | #define PE_MAX_MTU 1500 | 61 | #define PE_MAX_MTU 9000 |
67 | #define PE_DEF_MTU ETH_DATA_LEN | 62 | #define PE_DEF_MTU ETH_DATA_LEN |
68 | 63 | ||
69 | #define DEFAULT_MSG_ENABLE \ | 64 | #define DEFAULT_MSG_ENABLE \ |
@@ -76,16 +71,6 @@ | |||
76 | NETIF_MSG_RX_ERR | \ | 71 | NETIF_MSG_RX_ERR | \ |
77 | NETIF_MSG_TX_ERR) | 72 | NETIF_MSG_TX_ERR) |
78 | 73 | ||
79 | #define TX_DESC(tx, num) ((tx)->chan.ring_virt[(num) & (TX_RING_SIZE-1)]) | ||
80 | #define TX_DESC_INFO(tx, num) ((tx)->ring_info[(num) & (TX_RING_SIZE-1)]) | ||
81 | #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_BUFF(rx, num) ((rx)->buffers[(num) & (RX_RING_SIZE-1)]) | ||
84 | |||
85 | #define RING_USED(ring) (((ring)->next_to_fill - (ring)->next_to_clean) \ | ||
86 | & ((ring)->size - 1)) | ||
87 | #define RING_AVAIL(ring) ((ring->size) - RING_USED(ring)) | ||
88 | |||
89 | MODULE_LICENSE("GPL"); | 74 | MODULE_LICENSE("GPL"); |
90 | MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>"); | 75 | MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>"); |
91 | MODULE_DESCRIPTION("PA Semi PWRficient Ethernet driver"); | 76 | MODULE_DESCRIPTION("PA Semi PWRficient Ethernet driver"); |
@@ -94,6 +79,8 @@ static int debug = -1; /* -1 == use DEFAULT_MSG_ENABLE as value */ | |||
94 | module_param(debug, int, 0); | 79 | module_param(debug, int, 0); |
95 | MODULE_PARM_DESC(debug, "PA Semi MAC bitmapped debugging message enable value"); | 80 | MODULE_PARM_DESC(debug, "PA Semi MAC bitmapped debugging message enable value"); |
96 | 81 | ||
82 | extern const struct ethtool_ops pasemi_mac_ethtool_ops; | ||
83 | |||
97 | static int translation_enabled(void) | 84 | static int translation_enabled(void) |
98 | { | 85 | { |
99 | #if defined(CONFIG_PPC_PASEMI_IOMMU_DMA_FORCE) | 86 | #if defined(CONFIG_PPC_PASEMI_IOMMU_DMA_FORCE) |
@@ -322,6 +309,103 @@ static int pasemi_mac_unmap_tx_skb(struct pasemi_mac *mac, | |||
322 | return (nfrags + 3) & ~1; | 309 | return (nfrags + 3) & ~1; |
323 | } | 310 | } |
324 | 311 | ||
312 | static struct pasemi_mac_csring *pasemi_mac_setup_csring(struct pasemi_mac *mac) | ||
313 | { | ||
314 | struct pasemi_mac_csring *ring; | ||
315 | u32 val; | ||
316 | unsigned int cfg; | ||
317 | int chno; | ||
318 | |||
319 | ring = pasemi_dma_alloc_chan(TXCHAN, sizeof(struct pasemi_mac_csring), | ||
320 | offsetof(struct pasemi_mac_csring, chan)); | ||
321 | |||
322 | if (!ring) { | ||
323 | dev_err(&mac->pdev->dev, "Can't allocate checksum channel\n"); | ||
324 | goto out_chan; | ||
325 | } | ||
326 | |||
327 | chno = ring->chan.chno; | ||
328 | |||
329 | ring->size = CS_RING_SIZE; | ||
330 | ring->next_to_fill = 0; | ||
331 | |||
332 | /* Allocate descriptors */ | ||
333 | if (pasemi_dma_alloc_ring(&ring->chan, CS_RING_SIZE)) | ||
334 | goto out_ring_desc; | ||
335 | |||
336 | write_dma_reg(PAS_DMA_TXCHAN_BASEL(chno), | ||
337 | PAS_DMA_TXCHAN_BASEL_BRBL(ring->chan.ring_dma)); | ||
338 | val = PAS_DMA_TXCHAN_BASEU_BRBH(ring->chan.ring_dma >> 32); | ||
339 | val |= PAS_DMA_TXCHAN_BASEU_SIZ(CS_RING_SIZE >> 3); | ||
340 | |||
341 | write_dma_reg(PAS_DMA_TXCHAN_BASEU(chno), val); | ||
342 | |||
343 | ring->events[0] = pasemi_dma_alloc_flag(); | ||
344 | ring->events[1] = pasemi_dma_alloc_flag(); | ||
345 | if (ring->events[0] < 0 || ring->events[1] < 0) | ||
346 | goto out_flags; | ||
347 | |||
348 | pasemi_dma_clear_flag(ring->events[0]); | ||
349 | pasemi_dma_clear_flag(ring->events[1]); | ||
350 | |||
351 | ring->fun = pasemi_dma_alloc_fun(); | ||
352 | if (ring->fun < 0) | ||
353 | goto out_fun; | ||
354 | |||
355 | cfg = PAS_DMA_TXCHAN_CFG_TY_FUNC | PAS_DMA_TXCHAN_CFG_UP | | ||
356 | PAS_DMA_TXCHAN_CFG_TATTR(ring->fun) | | ||
357 | PAS_DMA_TXCHAN_CFG_LPSQ | PAS_DMA_TXCHAN_CFG_LPDQ; | ||
358 | |||
359 | if (translation_enabled()) | ||
360 | cfg |= PAS_DMA_TXCHAN_CFG_TRD | PAS_DMA_TXCHAN_CFG_TRR; | ||
361 | |||
362 | write_dma_reg(PAS_DMA_TXCHAN_CFG(chno), cfg); | ||
363 | |||
364 | /* enable channel */ | ||
365 | pasemi_dma_start_chan(&ring->chan, PAS_DMA_TXCHAN_TCMDSTA_SZ | | ||
366 | PAS_DMA_TXCHAN_TCMDSTA_DB | | ||
367 | PAS_DMA_TXCHAN_TCMDSTA_DE | | ||
368 | PAS_DMA_TXCHAN_TCMDSTA_DA); | ||
369 | |||
370 | return ring; | ||
371 | |||
372 | out_fun: | ||
373 | out_flags: | ||
374 | if (ring->events[0] >= 0) | ||
375 | pasemi_dma_free_flag(ring->events[0]); | ||
376 | if (ring->events[1] >= 0) | ||
377 | pasemi_dma_free_flag(ring->events[1]); | ||
378 | pasemi_dma_free_ring(&ring->chan); | ||
379 | out_ring_desc: | ||
380 | pasemi_dma_free_chan(&ring->chan); | ||
381 | out_chan: | ||
382 | |||
383 | return NULL; | ||
384 | } | ||
385 | |||
386 | static void pasemi_mac_setup_csrings(struct pasemi_mac *mac) | ||
387 | { | ||
388 | int i; | ||
389 | mac->cs[0] = pasemi_mac_setup_csring(mac); | ||
390 | if (mac->type == MAC_TYPE_XAUI) | ||
391 | mac->cs[1] = pasemi_mac_setup_csring(mac); | ||
392 | else | ||
393 | mac->cs[1] = 0; | ||
394 | |||
395 | for (i = 0; i < MAX_CS; i++) | ||
396 | if (mac->cs[i]) | ||
397 | mac->num_cs++; | ||
398 | } | ||
399 | |||
400 | static void pasemi_mac_free_csring(struct pasemi_mac_csring *csring) | ||
401 | { | ||
402 | pasemi_dma_stop_chan(&csring->chan); | ||
403 | pasemi_dma_free_flag(csring->events[0]); | ||
404 | pasemi_dma_free_flag(csring->events[1]); | ||
405 | pasemi_dma_free_ring(&csring->chan); | ||
406 | pasemi_dma_free_chan(&csring->chan); | ||
407 | } | ||
408 | |||
325 | static int pasemi_mac_setup_rx_resources(const struct net_device *dev) | 409 | static int pasemi_mac_setup_rx_resources(const struct net_device *dev) |
326 | { | 410 | { |
327 | struct pasemi_mac_rxring *ring; | 411 | struct pasemi_mac_rxring *ring; |
@@ -445,7 +529,7 @@ pasemi_mac_setup_tx_resources(const struct net_device *dev) | |||
445 | cfg = PAS_DMA_TXCHAN_CFG_TY_IFACE | | 529 | cfg = PAS_DMA_TXCHAN_CFG_TY_IFACE | |
446 | PAS_DMA_TXCHAN_CFG_TATTR(mac->dma_if) | | 530 | PAS_DMA_TXCHAN_CFG_TATTR(mac->dma_if) | |
447 | PAS_DMA_TXCHAN_CFG_UP | | 531 | PAS_DMA_TXCHAN_CFG_UP | |
448 | PAS_DMA_TXCHAN_CFG_WT(2); | 532 | PAS_DMA_TXCHAN_CFG_WT(4); |
449 | 533 | ||
450 | if (translation_enabled()) | 534 | if (translation_enabled()) |
451 | cfg |= PAS_DMA_TXCHAN_CFG_TRD | PAS_DMA_TXCHAN_CFG_TRR; | 535 | cfg |= PAS_DMA_TXCHAN_CFG_TRD | PAS_DMA_TXCHAN_CFG_TRR; |
@@ -810,13 +894,21 @@ restart: | |||
810 | u64 mactx = TX_DESC(txring, i); | 894 | u64 mactx = TX_DESC(txring, i); |
811 | struct sk_buff *skb; | 895 | struct sk_buff *skb; |
812 | 896 | ||
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) || | 897 | if ((mactx & XCT_MACTX_E) || |
817 | (*chan->status & PAS_STATUS_ERROR)) | 898 | (*chan->status & PAS_STATUS_ERROR)) |
818 | pasemi_mac_tx_error(mac, mactx); | 899 | pasemi_mac_tx_error(mac, mactx); |
819 | 900 | ||
901 | /* Skip over control descriptors */ | ||
902 | if (!(mactx & XCT_MACTX_LLEN_M)) { | ||
903 | TX_DESC(txring, i) = 0; | ||
904 | TX_DESC(txring, i+1) = 0; | ||
905 | buf_count = 2; | ||
906 | continue; | ||
907 | } | ||
908 | |||
909 | skb = TX_DESC_INFO(txring, i+1).skb; | ||
910 | nr_frags = TX_DESC_INFO(txring, i).dma; | ||
911 | |||
820 | if (unlikely(mactx & XCT_MACTX_O)) | 912 | if (unlikely(mactx & XCT_MACTX_O)) |
821 | /* Not yet transmitted */ | 913 | /* Not yet transmitted */ |
822 | break; | 914 | break; |
@@ -1041,13 +1133,7 @@ static int pasemi_mac_open(struct net_device *dev) | |||
1041 | { | 1133 | { |
1042 | struct pasemi_mac *mac = netdev_priv(dev); | 1134 | struct pasemi_mac *mac = netdev_priv(dev); |
1043 | unsigned int flags; | 1135 | unsigned int flags; |
1044 | int ret; | 1136 | int i, ret; |
1045 | |||
1046 | /* enable rx section */ | ||
1047 | write_dma_reg(PAS_DMA_COM_RXCMD, PAS_DMA_COM_RXCMD_EN); | ||
1048 | |||
1049 | /* enable tx section */ | ||
1050 | write_dma_reg(PAS_DMA_COM_TXCMD, PAS_DMA_COM_TXCMD_EN); | ||
1051 | 1137 | ||
1052 | flags = PAS_MAC_CFG_TXP_FCE | PAS_MAC_CFG_TXP_FPC(3) | | 1138 | flags = PAS_MAC_CFG_TXP_FCE | PAS_MAC_CFG_TXP_FPC(3) | |
1053 | PAS_MAC_CFG_TXP_SL(3) | PAS_MAC_CFG_TXP_COB(0xf) | | 1139 | PAS_MAC_CFG_TXP_SL(3) | PAS_MAC_CFG_TXP_COB(0xf) | |
@@ -1064,6 +1150,16 @@ static int pasemi_mac_open(struct net_device *dev) | |||
1064 | if (!mac->tx) | 1150 | if (!mac->tx) |
1065 | goto out_tx_ring; | 1151 | goto out_tx_ring; |
1066 | 1152 | ||
1153 | if (dev->mtu > 1500) { | ||
1154 | pasemi_mac_setup_csrings(mac); | ||
1155 | if (!mac->num_cs) | ||
1156 | goto out_tx_ring; | ||
1157 | } | ||
1158 | |||
1159 | /* Zero out rmon counters */ | ||
1160 | for (i = 0; i < 32; i++) | ||
1161 | write_mac_reg(mac, PAS_MAC_RMON(i), 0); | ||
1162 | |||
1067 | /* 0x3ff with 33MHz clock is about 31us */ | 1163 | /* 0x3ff with 33MHz clock is about 31us */ |
1068 | write_iob_reg(PAS_IOB_DMA_COM_TIMEOUTCFG, | 1164 | write_iob_reg(PAS_IOB_DMA_COM_TIMEOUTCFG, |
1069 | PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0x3ff)); | 1165 | PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0x3ff)); |
@@ -1247,7 +1343,7 @@ static int pasemi_mac_close(struct net_device *dev) | |||
1247 | { | 1343 | { |
1248 | struct pasemi_mac *mac = netdev_priv(dev); | 1344 | struct pasemi_mac *mac = netdev_priv(dev); |
1249 | unsigned int sta; | 1345 | unsigned int sta; |
1250 | int rxch, txch; | 1346 | int rxch, txch, i; |
1251 | 1347 | ||
1252 | rxch = rx_ring(mac)->chan.chno; | 1348 | rxch = rx_ring(mac)->chan.chno; |
1253 | txch = tx_ring(mac)->chan.chno; | 1349 | txch = tx_ring(mac)->chan.chno; |
@@ -1292,6 +1388,9 @@ static int pasemi_mac_close(struct net_device *dev) | |||
1292 | free_irq(mac->tx->chan.irq, mac->tx); | 1388 | free_irq(mac->tx->chan.irq, mac->tx); |
1293 | free_irq(mac->rx->chan.irq, mac->rx); | 1389 | free_irq(mac->rx->chan.irq, mac->rx); |
1294 | 1390 | ||
1391 | for (i = 0; i < mac->num_cs; i++) | ||
1392 | pasemi_mac_free_csring(mac->cs[i]); | ||
1393 | |||
1295 | /* Free resources */ | 1394 | /* Free resources */ |
1296 | pasemi_mac_free_rx_resources(mac); | 1395 | pasemi_mac_free_rx_resources(mac); |
1297 | pasemi_mac_free_tx_resources(mac); | 1396 | pasemi_mac_free_tx_resources(mac); |
@@ -1299,35 +1398,113 @@ static int pasemi_mac_close(struct net_device *dev) | |||
1299 | return 0; | 1398 | return 0; |
1300 | } | 1399 | } |
1301 | 1400 | ||
1401 | static void pasemi_mac_queue_csdesc(const struct sk_buff *skb, | ||
1402 | const dma_addr_t *map, | ||
1403 | const unsigned int *map_size, | ||
1404 | struct pasemi_mac_txring *txring, | ||
1405 | struct pasemi_mac_csring *csring) | ||
1406 | { | ||
1407 | u64 fund; | ||
1408 | dma_addr_t cs_dest; | ||
1409 | const int nh_off = skb_network_offset(skb); | ||
1410 | const int nh_len = skb_network_header_len(skb); | ||
1411 | const int nfrags = skb_shinfo(skb)->nr_frags; | ||
1412 | int cs_size, i, fill, hdr, cpyhdr, evt; | ||
1413 | dma_addr_t csdma; | ||
1414 | |||
1415 | fund = XCT_FUN_ST | XCT_FUN_RR_8BRES | | ||
1416 | XCT_FUN_O | XCT_FUN_FUN(csring->fun) | | ||
1417 | XCT_FUN_CRM_SIG | XCT_FUN_LLEN(skb->len - nh_off) | | ||
1418 | XCT_FUN_SHL(nh_len >> 2) | XCT_FUN_SE; | ||
1419 | |||
1420 | switch (ip_hdr(skb)->protocol) { | ||
1421 | case IPPROTO_TCP: | ||
1422 | fund |= XCT_FUN_SIG_TCP4; | ||
1423 | /* TCP checksum is 16 bytes into the header */ | ||
1424 | cs_dest = map[0] + skb_transport_offset(skb) + 16; | ||
1425 | break; | ||
1426 | case IPPROTO_UDP: | ||
1427 | fund |= XCT_FUN_SIG_UDP4; | ||
1428 | /* UDP checksum is 6 bytes into the header */ | ||
1429 | cs_dest = map[0] + skb_transport_offset(skb) + 6; | ||
1430 | break; | ||
1431 | default: | ||
1432 | BUG(); | ||
1433 | } | ||
1434 | |||
1435 | /* Do the checksum offloaded */ | ||
1436 | fill = csring->next_to_fill; | ||
1437 | hdr = fill; | ||
1438 | |||
1439 | CS_DESC(csring, fill++) = fund; | ||
1440 | /* Room for 8BRES. Checksum result is really 2 bytes into it */ | ||
1441 | csdma = csring->chan.ring_dma + (fill & (CS_RING_SIZE-1)) * 8 + 2; | ||
1442 | CS_DESC(csring, fill++) = 0; | ||
1443 | |||
1444 | CS_DESC(csring, fill) = XCT_PTR_LEN(map_size[0]-nh_off) | XCT_PTR_ADDR(map[0]+nh_off); | ||
1445 | for (i = 1; i <= nfrags; i++) | ||
1446 | CS_DESC(csring, fill+i) = XCT_PTR_LEN(map_size[i]) | XCT_PTR_ADDR(map[i]); | ||
1447 | |||
1448 | fill += i; | ||
1449 | if (fill & 1) | ||
1450 | fill++; | ||
1451 | |||
1452 | /* Copy the result into the TCP packet */ | ||
1453 | cpyhdr = fill; | ||
1454 | CS_DESC(csring, fill++) = XCT_FUN_O | XCT_FUN_FUN(csring->fun) | | ||
1455 | XCT_FUN_LLEN(2) | XCT_FUN_SE; | ||
1456 | CS_DESC(csring, fill++) = XCT_PTR_LEN(2) | XCT_PTR_ADDR(cs_dest) | XCT_PTR_T; | ||
1457 | CS_DESC(csring, fill++) = XCT_PTR_LEN(2) | XCT_PTR_ADDR(csdma); | ||
1458 | fill++; | ||
1459 | |||
1460 | evt = !csring->last_event; | ||
1461 | csring->last_event = evt; | ||
1462 | |||
1463 | /* Event handshaking with MAC TX */ | ||
1464 | CS_DESC(csring, fill++) = CTRL_CMD_T | CTRL_CMD_META_EVT | CTRL_CMD_O | | ||
1465 | CTRL_CMD_ETYPE_SET | CTRL_CMD_REG(csring->events[evt]); | ||
1466 | CS_DESC(csring, fill++) = 0; | ||
1467 | CS_DESC(csring, fill++) = CTRL_CMD_T | CTRL_CMD_META_EVT | CTRL_CMD_O | | ||
1468 | CTRL_CMD_ETYPE_WCLR | CTRL_CMD_REG(csring->events[!evt]); | ||
1469 | CS_DESC(csring, fill++) = 0; | ||
1470 | csring->next_to_fill = fill & (CS_RING_SIZE-1); | ||
1471 | |||
1472 | cs_size = fill - hdr; | ||
1473 | write_dma_reg(PAS_DMA_TXCHAN_INCR(csring->chan.chno), (cs_size) >> 1); | ||
1474 | |||
1475 | /* TX-side event handshaking */ | ||
1476 | fill = txring->next_to_fill; | ||
1477 | TX_DESC(txring, fill++) = CTRL_CMD_T | CTRL_CMD_META_EVT | CTRL_CMD_O | | ||
1478 | CTRL_CMD_ETYPE_WSET | CTRL_CMD_REG(csring->events[evt]); | ||
1479 | TX_DESC(txring, fill++) = 0; | ||
1480 | TX_DESC(txring, fill++) = CTRL_CMD_T | CTRL_CMD_META_EVT | CTRL_CMD_O | | ||
1481 | CTRL_CMD_ETYPE_CLR | CTRL_CMD_REG(csring->events[!evt]); | ||
1482 | TX_DESC(txring, fill++) = 0; | ||
1483 | txring->next_to_fill = fill; | ||
1484 | |||
1485 | write_dma_reg(PAS_DMA_TXCHAN_INCR(txring->chan.chno), 2); | ||
1486 | |||
1487 | return; | ||
1488 | } | ||
1489 | |||
1302 | static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) | 1490 | static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) |
1303 | { | 1491 | { |
1304 | struct pasemi_mac *mac = netdev_priv(dev); | 1492 | struct pasemi_mac * const mac = netdev_priv(dev); |
1305 | struct pasemi_mac_txring *txring; | 1493 | struct pasemi_mac_txring * const txring = tx_ring(mac); |
1306 | u64 dflags, mactx; | 1494 | struct pasemi_mac_csring *csring; |
1495 | u64 dflags = 0; | ||
1496 | u64 mactx; | ||
1307 | dma_addr_t map[MAX_SKB_FRAGS+1]; | 1497 | dma_addr_t map[MAX_SKB_FRAGS+1]; |
1308 | unsigned int map_size[MAX_SKB_FRAGS+1]; | 1498 | unsigned int map_size[MAX_SKB_FRAGS+1]; |
1309 | unsigned long flags; | 1499 | unsigned long flags; |
1310 | int i, nfrags; | 1500 | int i, nfrags; |
1311 | int fill; | 1501 | int fill; |
1502 | const int nh_off = skb_network_offset(skb); | ||
1503 | const int nh_len = skb_network_header_len(skb); | ||
1312 | 1504 | ||
1313 | dflags = XCT_MACTX_O | XCT_MACTX_ST | XCT_MACTX_CRC_PAD; | 1505 | prefetch(&txring->ring_info); |
1314 | |||
1315 | if (skb->ip_summed == CHECKSUM_PARTIAL) { | ||
1316 | const unsigned char *nh = skb_network_header(skb); | ||
1317 | 1506 | ||
1318 | switch (ip_hdr(skb)->protocol) { | 1507 | dflags = XCT_MACTX_O | XCT_MACTX_ST | XCT_MACTX_CRC_PAD; |
1319 | case IPPROTO_TCP: | ||
1320 | dflags |= XCT_MACTX_CSUM_TCP; | ||
1321 | dflags |= XCT_MACTX_IPH(skb_network_header_len(skb) >> 2); | ||
1322 | dflags |= XCT_MACTX_IPO(nh - skb->data); | ||
1323 | break; | ||
1324 | case IPPROTO_UDP: | ||
1325 | dflags |= XCT_MACTX_CSUM_UDP; | ||
1326 | dflags |= XCT_MACTX_IPH(skb_network_header_len(skb) >> 2); | ||
1327 | dflags |= XCT_MACTX_IPO(nh - skb->data); | ||
1328 | break; | ||
1329 | } | ||
1330 | } | ||
1331 | 1508 | ||
1332 | nfrags = skb_shinfo(skb)->nr_frags; | 1509 | nfrags = skb_shinfo(skb)->nr_frags; |
1333 | 1510 | ||
@@ -1350,24 +1527,46 @@ static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev) | |||
1350 | } | 1527 | } |
1351 | } | 1528 | } |
1352 | 1529 | ||
1353 | mactx = dflags | XCT_MACTX_LLEN(skb->len); | 1530 | if (skb->ip_summed == CHECKSUM_PARTIAL && skb->len <= 1540) { |
1531 | switch (ip_hdr(skb)->protocol) { | ||
1532 | case IPPROTO_TCP: | ||
1533 | dflags |= XCT_MACTX_CSUM_TCP; | ||
1534 | dflags |= XCT_MACTX_IPH(nh_len >> 2); | ||
1535 | dflags |= XCT_MACTX_IPO(nh_off); | ||
1536 | break; | ||
1537 | case IPPROTO_UDP: | ||
1538 | dflags |= XCT_MACTX_CSUM_UDP; | ||
1539 | dflags |= XCT_MACTX_IPH(nh_len >> 2); | ||
1540 | dflags |= XCT_MACTX_IPO(nh_off); | ||
1541 | break; | ||
1542 | default: | ||
1543 | WARN_ON(1); | ||
1544 | } | ||
1545 | } | ||
1354 | 1546 | ||
1355 | txring = tx_ring(mac); | 1547 | mactx = dflags | XCT_MACTX_LLEN(skb->len); |
1356 | 1548 | ||
1357 | spin_lock_irqsave(&txring->lock, flags); | 1549 | spin_lock_irqsave(&txring->lock, flags); |
1358 | 1550 | ||
1359 | fill = txring->next_to_fill; | ||
1360 | |||
1361 | /* Avoid stepping on the same cache line that the DMA controller | 1551 | /* Avoid stepping on the same cache line that the DMA controller |
1362 | * is currently about to send, so leave at least 8 words available. | 1552 | * is currently about to send, so leave at least 8 words available. |
1363 | * Total free space needed is mactx + fragments + 8 | 1553 | * Total free space needed is mactx + fragments + 8 |
1364 | */ | 1554 | */ |
1365 | if (RING_AVAIL(txring) < nfrags + 10) { | 1555 | if (RING_AVAIL(txring) < nfrags + 14) { |
1366 | /* no room -- stop the queue and wait for tx intr */ | 1556 | /* no room -- stop the queue and wait for tx intr */ |
1367 | netif_stop_queue(dev); | 1557 | netif_stop_queue(dev); |
1368 | goto out_err; | 1558 | goto out_err; |
1369 | } | 1559 | } |
1370 | 1560 | ||
1561 | /* Queue up checksum + event descriptors, if needed */ | ||
1562 | if (mac->num_cs && skb->ip_summed == CHECKSUM_PARTIAL && skb->len > 1540) { | ||
1563 | csring = mac->cs[mac->last_cs]; | ||
1564 | mac->last_cs = (mac->last_cs + 1) % mac->num_cs; | ||
1565 | |||
1566 | pasemi_mac_queue_csdesc(skb, map, map_size, txring, csring); | ||
1567 | } | ||
1568 | |||
1569 | fill = txring->next_to_fill; | ||
1371 | TX_DESC(txring, fill) = mactx; | 1570 | TX_DESC(txring, fill) = mactx; |
1372 | TX_DESC_INFO(txring, fill).dma = nfrags; | 1571 | TX_DESC_INFO(txring, fill).dma = nfrags; |
1373 | fill++; | 1572 | fill++; |
@@ -1445,8 +1644,9 @@ static int pasemi_mac_change_mtu(struct net_device *dev, int new_mtu) | |||
1445 | { | 1644 | { |
1446 | struct pasemi_mac *mac = netdev_priv(dev); | 1645 | struct pasemi_mac *mac = netdev_priv(dev); |
1447 | unsigned int reg; | 1646 | unsigned int reg; |
1448 | unsigned int rcmdsta; | 1647 | unsigned int rcmdsta = 0; |
1449 | int running; | 1648 | int running; |
1649 | int ret = 0; | ||
1450 | 1650 | ||
1451 | if (new_mtu < PE_MIN_MTU || new_mtu > PE_MAX_MTU) | 1651 | if (new_mtu < PE_MIN_MTU || new_mtu > PE_MAX_MTU) |
1452 | return -EINVAL; | 1652 | return -EINVAL; |
@@ -1468,6 +1668,16 @@ static int pasemi_mac_change_mtu(struct net_device *dev, int new_mtu) | |||
1468 | pasemi_mac_pause_rxint(mac); | 1668 | pasemi_mac_pause_rxint(mac); |
1469 | pasemi_mac_clean_rx(rx_ring(mac), RX_RING_SIZE); | 1669 | pasemi_mac_clean_rx(rx_ring(mac), RX_RING_SIZE); |
1470 | pasemi_mac_free_rx_buffers(mac); | 1670 | pasemi_mac_free_rx_buffers(mac); |
1671 | |||
1672 | } | ||
1673 | |||
1674 | /* Setup checksum channels if large MTU and none already allocated */ | ||
1675 | if (new_mtu > 1500 && !mac->num_cs) { | ||
1676 | pasemi_mac_setup_csrings(mac); | ||
1677 | if (!mac->num_cs) { | ||
1678 | ret = -ENOMEM; | ||
1679 | goto out; | ||
1680 | } | ||
1471 | } | 1681 | } |
1472 | 1682 | ||
1473 | /* Change maxf, i.e. what size frames are accepted. | 1683 | /* Change maxf, i.e. what size frames are accepted. |
@@ -1482,6 +1692,7 @@ static int pasemi_mac_change_mtu(struct net_device *dev, int new_mtu) | |||
1482 | /* MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */ | 1692 | /* MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */ |
1483 | mac->bufsz = new_mtu + ETH_HLEN + ETH_FCS_LEN + LOCAL_SKB_ALIGN + 128; | 1693 | mac->bufsz = new_mtu + ETH_HLEN + ETH_FCS_LEN + LOCAL_SKB_ALIGN + 128; |
1484 | 1694 | ||
1695 | out: | ||
1485 | if (running) { | 1696 | if (running) { |
1486 | write_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if), | 1697 | write_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if), |
1487 | rcmdsta | PAS_DMA_RXINT_RCMDSTA_EN); | 1698 | rcmdsta | PAS_DMA_RXINT_RCMDSTA_EN); |
@@ -1494,7 +1705,7 @@ static int pasemi_mac_change_mtu(struct net_device *dev, int new_mtu) | |||
1494 | pasemi_mac_intf_enable(mac); | 1705 | pasemi_mac_intf_enable(mac); |
1495 | } | 1706 | } |
1496 | 1707 | ||
1497 | return 0; | 1708 | return ret; |
1498 | } | 1709 | } |
1499 | 1710 | ||
1500 | static int __devinit | 1711 | static int __devinit |
@@ -1528,7 +1739,7 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1528 | netif_napi_add(dev, &mac->napi, pasemi_mac_poll, 64); | 1739 | netif_napi_add(dev, &mac->napi, pasemi_mac_poll, 64); |
1529 | 1740 | ||
1530 | dev->features = NETIF_F_IP_CSUM | NETIF_F_LLTX | NETIF_F_SG | | 1741 | dev->features = NETIF_F_IP_CSUM | NETIF_F_LLTX | NETIF_F_SG | |
1531 | NETIF_F_HIGHDMA; | 1742 | NETIF_F_HIGHDMA | NETIF_F_GSO; |
1532 | 1743 | ||
1533 | mac->lro_mgr.max_aggr = LRO_MAX_AGGR; | 1744 | mac->lro_mgr.max_aggr = LRO_MAX_AGGR; |
1534 | mac->lro_mgr.max_desc = MAX_LRO_DESCRIPTORS; | 1745 | mac->lro_mgr.max_desc = MAX_LRO_DESCRIPTORS; |
@@ -1590,6 +1801,7 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1590 | mac->bufsz = dev->mtu + ETH_HLEN + ETH_FCS_LEN + LOCAL_SKB_ALIGN + 128; | 1801 | mac->bufsz = dev->mtu + ETH_HLEN + ETH_FCS_LEN + LOCAL_SKB_ALIGN + 128; |
1591 | 1802 | ||
1592 | dev->change_mtu = pasemi_mac_change_mtu; | 1803 | dev->change_mtu = pasemi_mac_change_mtu; |
1804 | dev->ethtool_ops = &pasemi_mac_ethtool_ops; | ||
1593 | 1805 | ||
1594 | if (err) | 1806 | if (err) |
1595 | goto out; | 1807 | goto out; |
diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h index 99e7b9329a6f..1a115ec60b53 100644 --- a/drivers/net/pasemi_mac.h +++ b/drivers/net/pasemi_mac.h | |||
@@ -26,7 +26,14 @@ | |||
26 | #include <linux/spinlock.h> | 26 | #include <linux/spinlock.h> |
27 | #include <linux/phy.h> | 27 | #include <linux/phy.h> |
28 | 28 | ||
29 | /* Must be a power of two */ | ||
30 | #define RX_RING_SIZE 2048 | ||
31 | #define TX_RING_SIZE 4096 | ||
32 | #define CS_RING_SIZE (TX_RING_SIZE*2) | ||
33 | |||
34 | |||
29 | #define MAX_LRO_DESCRIPTORS 8 | 35 | #define MAX_LRO_DESCRIPTORS 8 |
36 | #define MAX_CS 2 | ||
30 | 37 | ||
31 | struct pasemi_mac_txring { | 38 | struct pasemi_mac_txring { |
32 | struct pasemi_dmachan chan; /* Must be first */ | 39 | struct pasemi_dmachan chan; /* Must be first */ |
@@ -51,6 +58,15 @@ struct pasemi_mac_rxring { | |||
51 | struct pasemi_mac *mac; /* Needed in intr handler */ | 58 | struct pasemi_mac *mac; /* Needed in intr handler */ |
52 | }; | 59 | }; |
53 | 60 | ||
61 | struct pasemi_mac_csring { | ||
62 | struct pasemi_dmachan chan; | ||
63 | unsigned int size; | ||
64 | unsigned int next_to_fill; | ||
65 | int events[2]; | ||
66 | int last_event; | ||
67 | int fun; | ||
68 | }; | ||
69 | |||
54 | struct pasemi_mac { | 70 | struct pasemi_mac { |
55 | struct net_device *netdev; | 71 | struct net_device *netdev; |
56 | struct pci_dev *pdev; | 72 | struct pci_dev *pdev; |
@@ -60,10 +76,12 @@ struct pasemi_mac { | |||
60 | struct napi_struct napi; | 76 | struct napi_struct napi; |
61 | 77 | ||
62 | int bufsz; /* RX ring buffer size */ | 78 | int bufsz; /* RX ring buffer size */ |
79 | int last_cs; | ||
80 | int num_cs; | ||
81 | u32 dma_if; | ||
63 | u8 type; | 82 | u8 type; |
64 | #define MAC_TYPE_GMAC 1 | 83 | #define MAC_TYPE_GMAC 1 |
65 | #define MAC_TYPE_XAUI 2 | 84 | #define MAC_TYPE_XAUI 2 |
66 | u32 dma_if; | ||
67 | 85 | ||
68 | u8 mac_addr[6]; | 86 | u8 mac_addr[6]; |
69 | 87 | ||
@@ -74,6 +92,7 @@ struct pasemi_mac { | |||
74 | 92 | ||
75 | struct pasemi_mac_txring *tx; | 93 | struct pasemi_mac_txring *tx; |
76 | struct pasemi_mac_rxring *rx; | 94 | struct pasemi_mac_rxring *rx; |
95 | struct pasemi_mac_csring *cs[MAX_CS]; | ||
77 | char tx_irq_name[10]; /* "eth%d tx" */ | 96 | char tx_irq_name[10]; /* "eth%d tx" */ |
78 | char rx_irq_name[10]; /* "eth%d rx" */ | 97 | char rx_irq_name[10]; /* "eth%d rx" */ |
79 | int link; | 98 | int link; |
@@ -90,6 +109,16 @@ struct pasemi_mac_buffer { | |||
90 | dma_addr_t dma; | 109 | dma_addr_t dma; |
91 | }; | 110 | }; |
92 | 111 | ||
112 | #define TX_DESC(tx, num) ((tx)->chan.ring_virt[(num) & (TX_RING_SIZE-1)]) | ||
113 | #define TX_DESC_INFO(tx, num) ((tx)->ring_info[(num) & (TX_RING_SIZE-1)]) | ||
114 | #define RX_DESC(rx, num) ((rx)->chan.ring_virt[(num) & (RX_RING_SIZE-1)]) | ||
115 | #define RX_DESC_INFO(rx, num) ((rx)->ring_info[(num) & (RX_RING_SIZE-1)]) | ||
116 | #define RX_BUFF(rx, num) ((rx)->buffers[(num) & (RX_RING_SIZE-1)]) | ||
117 | #define CS_DESC(cs, num) ((cs)->chan.ring_virt[(num) & (CS_RING_SIZE-1)]) | ||
118 | |||
119 | #define RING_USED(ring) (((ring)->next_to_fill - (ring)->next_to_clean) \ | ||
120 | & ((ring)->size - 1)) | ||
121 | #define RING_AVAIL(ring) ((ring->size) - RING_USED(ring)) | ||
93 | 122 | ||
94 | /* PCI register offsets and formats */ | 123 | /* PCI register offsets and formats */ |
95 | 124 | ||
@@ -101,6 +130,7 @@ enum { | |||
101 | PAS_MAC_CFG_ADR0 = 0x8c, | 130 | PAS_MAC_CFG_ADR0 = 0x8c, |
102 | PAS_MAC_CFG_ADR1 = 0x90, | 131 | PAS_MAC_CFG_ADR1 = 0x90, |
103 | PAS_MAC_CFG_TXP = 0x98, | 132 | PAS_MAC_CFG_TXP = 0x98, |
133 | PAS_MAC_CFG_RMON = 0x100, | ||
104 | PAS_MAC_IPC_CHNL = 0x208, | 134 | PAS_MAC_IPC_CHNL = 0x208, |
105 | }; | 135 | }; |
106 | 136 | ||
@@ -172,6 +202,8 @@ enum { | |||
172 | #define PAS_MAC_CFG_TXP_TIFG(x) (((x) << PAS_MAC_CFG_TXP_TIFG_S) & \ | 202 | #define PAS_MAC_CFG_TXP_TIFG(x) (((x) << PAS_MAC_CFG_TXP_TIFG_S) & \ |
173 | PAS_MAC_CFG_TXP_TIFG_M) | 203 | PAS_MAC_CFG_TXP_TIFG_M) |
174 | 204 | ||
205 | #define PAS_MAC_RMON(r) (0x100+(r)*4) | ||
206 | |||
175 | #define PAS_MAC_IPC_CHNL_DCHNO_M 0x003f0000 | 207 | #define PAS_MAC_IPC_CHNL_DCHNO_M 0x003f0000 |
176 | #define PAS_MAC_IPC_CHNL_DCHNO_S 16 | 208 | #define PAS_MAC_IPC_CHNL_DCHNO_S 16 |
177 | #define PAS_MAC_IPC_CHNL_DCHNO(x) (((x) << PAS_MAC_IPC_CHNL_DCHNO_S) & \ | 209 | #define PAS_MAC_IPC_CHNL_DCHNO(x) (((x) << PAS_MAC_IPC_CHNL_DCHNO_S) & \ |
@@ -181,4 +213,5 @@ enum { | |||
181 | #define PAS_MAC_IPC_CHNL_BCH(x) (((x) << PAS_MAC_IPC_CHNL_BCH_S) & \ | 213 | #define PAS_MAC_IPC_CHNL_BCH(x) (((x) << PAS_MAC_IPC_CHNL_BCH_S) & \ |
182 | PAS_MAC_IPC_CHNL_BCH_M) | 214 | PAS_MAC_IPC_CHNL_BCH_M) |
183 | 215 | ||
216 | |||
184 | #endif /* PASEMI_MAC_H */ | 217 | #endif /* PASEMI_MAC_H */ |
diff --git a/drivers/net/pasemi_mac_ethtool.c b/drivers/net/pasemi_mac_ethtool.c new file mode 100644 index 000000000000..5e8df3afea64 --- /dev/null +++ b/drivers/net/pasemi_mac_ethtool.c | |||
@@ -0,0 +1,159 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2006-2008 PA Semi, Inc | ||
3 | * | ||
4 | * Ethtool hooks for the PA Semi PWRficient onchip 1G/10G Ethernet MACs | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | |||
21 | #include <linux/netdevice.h> | ||
22 | #include <linux/ethtool.h> | ||
23 | #include <linux/pci.h> | ||
24 | #include <linux/inet_lro.h> | ||
25 | |||
26 | #include <asm/pasemi_dma.h> | ||
27 | #include "pasemi_mac.h" | ||
28 | |||
29 | static struct { | ||
30 | const char str[ETH_GSTRING_LEN]; | ||
31 | } ethtool_stats_keys[] = { | ||
32 | { "rx-drops" }, | ||
33 | { "rx-bytes" }, | ||
34 | { "rx-packets" }, | ||
35 | { "rx-broadcast-packets" }, | ||
36 | { "rx-multicast-packets" }, | ||
37 | { "rx-crc-errors" }, | ||
38 | { "rx-undersize-errors" }, | ||
39 | { "rx-oversize-errors" }, | ||
40 | { "rx-short-fragment-errors" }, | ||
41 | { "rx-jabber-errors" }, | ||
42 | { "rx-64-byte-packets" }, | ||
43 | { "rx-65-127-byte-packets" }, | ||
44 | { "rx-128-255-byte-packets" }, | ||
45 | { "rx-256-511-byte-packets" }, | ||
46 | { "rx-512-1023-byte-packets" }, | ||
47 | { "rx-1024-1518-byte-packets" }, | ||
48 | { "rx-pause-frames" }, | ||
49 | { "tx-bytes" }, | ||
50 | { "tx-packets" }, | ||
51 | { "tx-broadcast-packets" }, | ||
52 | { "tx-multicast-packets" }, | ||
53 | { "tx-collisions" }, | ||
54 | { "tx-late-collisions" }, | ||
55 | { "tx-excessive-collisions" }, | ||
56 | { "tx-crc-errors" }, | ||
57 | { "tx-undersize-errors" }, | ||
58 | { "tx-oversize-errors" }, | ||
59 | { "tx-64-byte-packets" }, | ||
60 | { "tx-65-127-byte-packets" }, | ||
61 | { "tx-128-255-byte-packets" }, | ||
62 | { "tx-256-511-byte-packets" }, | ||
63 | { "tx-512-1023-byte-packets" }, | ||
64 | { "tx-1024-1518-byte-packets" }, | ||
65 | }; | ||
66 | |||
67 | static int | ||
68 | pasemi_mac_ethtool_get_settings(struct net_device *netdev, | ||
69 | struct ethtool_cmd *cmd) | ||
70 | { | ||
71 | struct pasemi_mac *mac = netdev_priv(netdev); | ||
72 | struct phy_device *phydev = mac->phydev; | ||
73 | |||
74 | return phy_ethtool_gset(phydev, cmd); | ||
75 | } | ||
76 | |||
77 | static void | ||
78 | pasemi_mac_ethtool_get_drvinfo(struct net_device *netdev, | ||
79 | struct ethtool_drvinfo *drvinfo) | ||
80 | { | ||
81 | struct pasemi_mac *mac; | ||
82 | mac = netdev_priv(netdev); | ||
83 | |||
84 | /* clear and fill out info */ | ||
85 | memset(drvinfo, 0, sizeof(struct ethtool_drvinfo)); | ||
86 | strncpy(drvinfo->driver, "pasemi_mac", 12); | ||
87 | strcpy(drvinfo->version, "N/A"); | ||
88 | strcpy(drvinfo->fw_version, "N/A"); | ||
89 | strncpy(drvinfo->bus_info, pci_name(mac->pdev), 32); | ||
90 | } | ||
91 | |||
92 | static u32 | ||
93 | pasemi_mac_ethtool_get_msglevel(struct net_device *netdev) | ||
94 | { | ||
95 | struct pasemi_mac *mac = netdev_priv(netdev); | ||
96 | return mac->msg_enable; | ||
97 | } | ||
98 | |||
99 | static void | ||
100 | pasemi_mac_ethtool_set_msglevel(struct net_device *netdev, | ||
101 | u32 level) | ||
102 | { | ||
103 | struct pasemi_mac *mac = netdev_priv(netdev); | ||
104 | mac->msg_enable = level; | ||
105 | } | ||
106 | |||
107 | |||
108 | static void | ||
109 | pasemi_mac_ethtool_get_ringparam(struct net_device *netdev, | ||
110 | struct ethtool_ringparam *ering) | ||
111 | { | ||
112 | struct pasemi_mac *mac = netdev->priv; | ||
113 | |||
114 | ering->tx_max_pending = TX_RING_SIZE/2; | ||
115 | ering->tx_pending = RING_USED(mac->tx)/2; | ||
116 | ering->rx_max_pending = RX_RING_SIZE/4; | ||
117 | ering->rx_pending = RING_USED(mac->rx)/4; | ||
118 | } | ||
119 | |||
120 | static int pasemi_mac_get_sset_count(struct net_device *netdev, int sset) | ||
121 | { | ||
122 | switch (sset) { | ||
123 | case ETH_SS_STATS: | ||
124 | return ARRAY_SIZE(ethtool_stats_keys); | ||
125 | default: | ||
126 | return -EOPNOTSUPP; | ||
127 | } | ||
128 | } | ||
129 | |||
130 | static void pasemi_mac_get_ethtool_stats(struct net_device *netdev, | ||
131 | struct ethtool_stats *stats, u64 *data) | ||
132 | { | ||
133 | struct pasemi_mac *mac = netdev->priv; | ||
134 | int i; | ||
135 | |||
136 | data[0] = pasemi_read_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if)) | ||
137 | >> PAS_DMA_RXINT_RCMDSTA_DROPS_S; | ||
138 | for (i = 0; i < 32; i++) | ||
139 | data[1+i] = pasemi_read_mac_reg(mac->dma_if, PAS_MAC_RMON(i)); | ||
140 | } | ||
141 | |||
142 | static void pasemi_mac_get_strings(struct net_device *netdev, u32 stringset, | ||
143 | u8 *data) | ||
144 | { | ||
145 | memcpy(data, ethtool_stats_keys, sizeof(ethtool_stats_keys)); | ||
146 | } | ||
147 | |||
148 | const struct ethtool_ops pasemi_mac_ethtool_ops = { | ||
149 | .get_settings = pasemi_mac_ethtool_get_settings, | ||
150 | .get_drvinfo = pasemi_mac_ethtool_get_drvinfo, | ||
151 | .get_msglevel = pasemi_mac_ethtool_get_msglevel, | ||
152 | .set_msglevel = pasemi_mac_ethtool_set_msglevel, | ||
153 | .get_link = ethtool_op_get_link, | ||
154 | .get_ringparam = pasemi_mac_ethtool_get_ringparam, | ||
155 | .get_strings = pasemi_mac_get_strings, | ||
156 | .get_sset_count = pasemi_mac_get_sset_count, | ||
157 | .get_ethtool_stats = pasemi_mac_get_ethtool_stats, | ||
158 | }; | ||
159 | |||