diff options
author | Olof Johansson <olof@lixom.net> | 2008-01-23 14:56:47 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-02-03 07:27:54 -0500 |
commit | ef1ea0b424d09452b27f5cb1a0c108b645cb25e0 (patch) | |
tree | 71987b531b7dc1f00d9e0c7a34259444fc2088e9 /drivers/net/pasemi_mac.c | |
parent | 5cea73b0f7d4d49e276b0c4842465890d00de861 (diff) |
pasemi_mac: add support for setting MTU
Currently keeping it at 1500 bytes or below since jumbo frames need
special checksum offload on TX.
Signed-off-by: Olof Johansson <olof@lixom.net>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/pasemi_mac.c')
-rw-r--r-- | drivers/net/pasemi_mac.c | 230 |
1 files changed, 158 insertions, 72 deletions
diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index 59dea3f829fc..059c6b04dc8f 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c | |||
@@ -62,6 +62,10 @@ | |||
62 | 62 | ||
63 | #define LRO_MAX_AGGR 64 | 63 | #define LRO_MAX_AGGR 64 |
64 | 64 | ||
65 | #define PE_MIN_MTU 64 | ||
66 | #define PE_MAX_MTU 1500 | ||
67 | #define PE_DEF_MTU ETH_DATA_LEN | ||
68 | |||
65 | #define DEFAULT_MSG_ENABLE \ | 69 | #define DEFAULT_MSG_ENABLE \ |
66 | (NETIF_MSG_DRV | \ | 70 | (NETIF_MSG_DRV | \ |
67 | NETIF_MSG_PROBE | \ | 71 | NETIF_MSG_PROBE | \ |
@@ -82,8 +86,6 @@ | |||
82 | & ((ring)->size - 1)) | 86 | & ((ring)->size - 1)) |
83 | #define RING_AVAIL(ring) ((ring->size) - RING_USED(ring)) | 87 | #define RING_AVAIL(ring) ((ring->size) - RING_USED(ring)) |
84 | 88 | ||
85 | #define BUF_SIZE 1646 /* 1500 MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */ | ||
86 | |||
87 | MODULE_LICENSE("GPL"); | 89 | MODULE_LICENSE("GPL"); |
88 | MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>"); | 90 | MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>"); |
89 | MODULE_DESCRIPTION("PA Semi PWRficient Ethernet driver"); | 91 | MODULE_DESCRIPTION("PA Semi PWRficient Ethernet driver"); |
@@ -175,6 +177,24 @@ static int mac_to_intf(struct pasemi_mac *mac) | |||
175 | return -1; | 177 | return -1; |
176 | } | 178 | } |
177 | 179 | ||
180 | static void pasemi_mac_intf_disable(struct pasemi_mac *mac) | ||
181 | { | ||
182 | unsigned int flags; | ||
183 | |||
184 | flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG); | ||
185 | flags &= ~PAS_MAC_CFG_PCFG_PE; | ||
186 | write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags); | ||
187 | } | ||
188 | |||
189 | static void pasemi_mac_intf_enable(struct pasemi_mac *mac) | ||
190 | { | ||
191 | unsigned int flags; | ||
192 | |||
193 | flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG); | ||
194 | flags |= PAS_MAC_CFG_PCFG_PE; | ||
195 | write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags); | ||
196 | } | ||
197 | |||
178 | static int pasemi_get_mac_addr(struct pasemi_mac *mac) | 198 | static int pasemi_get_mac_addr(struct pasemi_mac *mac) |
179 | { | 199 | { |
180 | struct pci_dev *pdev = mac->pdev; | 200 | struct pci_dev *pdev = mac->pdev; |
@@ -480,7 +500,7 @@ static void pasemi_mac_free_tx_resources(struct pasemi_mac *mac) | |||
480 | 500 | ||
481 | } | 501 | } |
482 | 502 | ||
483 | static void pasemi_mac_free_rx_resources(struct pasemi_mac *mac) | 503 | static void pasemi_mac_free_rx_buffers(struct pasemi_mac *mac) |
484 | { | 504 | { |
485 | struct pasemi_mac_rxring *rx = rx_ring(mac); | 505 | struct pasemi_mac_rxring *rx = rx_ring(mac); |
486 | unsigned int i; | 506 | unsigned int i; |
@@ -500,7 +520,12 @@ static void pasemi_mac_free_rx_resources(struct pasemi_mac *mac) | |||
500 | } | 520 | } |
501 | 521 | ||
502 | for (i = 0; i < RX_RING_SIZE; i++) | 522 | for (i = 0; i < RX_RING_SIZE; i++) |
503 | RX_DESC(rx, i) = 0; | 523 | RX_BUFF(rx, i) = 0; |
524 | } | ||
525 | |||
526 | static void pasemi_mac_free_rx_resources(struct pasemi_mac *mac) | ||
527 | { | ||
528 | pasemi_mac_free_rx_buffers(mac); | ||
504 | 529 | ||
505 | dma_free_coherent(&mac->dma_pdev->dev, RX_RING_SIZE * sizeof(u64), | 530 | dma_free_coherent(&mac->dma_pdev->dev, RX_RING_SIZE * sizeof(u64), |
506 | rx_ring(mac)->buffers, rx_ring(mac)->buf_dma); | 531 | rx_ring(mac)->buffers, rx_ring(mac)->buf_dma); |
@@ -530,14 +555,14 @@ static void pasemi_mac_replenish_rx_ring(const struct net_device *dev, | |||
530 | /* Entry in use? */ | 555 | /* Entry in use? */ |
531 | WARN_ON(*buff); | 556 | WARN_ON(*buff); |
532 | 557 | ||
533 | skb = dev_alloc_skb(BUF_SIZE); | 558 | skb = dev_alloc_skb(mac->bufsz); |
534 | skb_reserve(skb, LOCAL_SKB_ALIGN); | 559 | skb_reserve(skb, LOCAL_SKB_ALIGN); |
535 | 560 | ||
536 | if (unlikely(!skb)) | 561 | if (unlikely(!skb)) |
537 | break; | 562 | break; |
538 | 563 | ||
539 | dma = pci_map_single(mac->dma_pdev, skb->data, | 564 | dma = pci_map_single(mac->dma_pdev, skb->data, |
540 | BUF_SIZE - LOCAL_SKB_ALIGN, | 565 | mac->bufsz - LOCAL_SKB_ALIGN, |
541 | PCI_DMA_FROMDEVICE); | 566 | PCI_DMA_FROMDEVICE); |
542 | 567 | ||
543 | if (unlikely(dma_mapping_error(dma))) { | 568 | if (unlikely(dma_mapping_error(dma))) { |
@@ -547,7 +572,7 @@ static void pasemi_mac_replenish_rx_ring(const struct net_device *dev, | |||
547 | 572 | ||
548 | info->skb = skb; | 573 | info->skb = skb; |
549 | info->dma = dma; | 574 | info->dma = dma; |
550 | *buff = XCT_RXB_LEN(BUF_SIZE) | XCT_RXB_ADDR(dma); | 575 | *buff = XCT_RXB_LEN(mac->bufsz) | XCT_RXB_ADDR(dma); |
551 | fill++; | 576 | fill++; |
552 | } | 577 | } |
553 | 578 | ||
@@ -677,7 +702,7 @@ static int pasemi_mac_clean_rx(struct pasemi_mac_rxring *rx, | |||
677 | 702 | ||
678 | len = (macrx & XCT_MACRX_LLEN_M) >> XCT_MACRX_LLEN_S; | 703 | len = (macrx & XCT_MACRX_LLEN_M) >> XCT_MACRX_LLEN_S; |
679 | 704 | ||
680 | pci_unmap_single(pdev, dma, BUF_SIZE-LOCAL_SKB_ALIGN, | 705 | pci_unmap_single(pdev, dma, mac->bufsz - LOCAL_SKB_ALIGN, |
681 | PCI_DMA_FROMDEVICE); | 706 | PCI_DMA_FROMDEVICE); |
682 | 707 | ||
683 | if (macrx & XCT_MACRX_CRC) { | 708 | if (macrx & XCT_MACRX_CRC) { |
@@ -901,24 +926,6 @@ static irqreturn_t pasemi_mac_tx_intr(int irq, void *data) | |||
901 | return IRQ_HANDLED; | 926 | return IRQ_HANDLED; |
902 | } | 927 | } |
903 | 928 | ||
904 | static void pasemi_mac_intf_disable(struct pasemi_mac *mac) | ||
905 | { | ||
906 | unsigned int flags; | ||
907 | |||
908 | flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG); | ||
909 | flags &= ~PAS_MAC_CFG_PCFG_PE; | ||
910 | write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags); | ||
911 | } | ||
912 | |||
913 | static void pasemi_mac_intf_enable(struct pasemi_mac *mac) | ||
914 | { | ||
915 | unsigned int flags; | ||
916 | |||
917 | flags = read_mac_reg(mac, PAS_MAC_CFG_PCFG); | ||
918 | flags |= PAS_MAC_CFG_PCFG_PE; | ||
919 | write_mac_reg(mac, PAS_MAC_CFG_PCFG, flags); | ||
920 | } | ||
921 | |||
922 | static void pasemi_adjust_link(struct net_device *dev) | 929 | static void pasemi_adjust_link(struct net_device *dev) |
923 | { | 930 | { |
924 | struct pasemi_mac *mac = netdev_priv(dev); | 931 | struct pasemi_mac *mac = netdev_priv(dev); |
@@ -1175,11 +1182,71 @@ out_rx_resources: | |||
1175 | 1182 | ||
1176 | #define MAX_RETRIES 5000 | 1183 | #define MAX_RETRIES 5000 |
1177 | 1184 | ||
1185 | static void pasemi_mac_pause_txchan(struct pasemi_mac *mac) | ||
1186 | { | ||
1187 | unsigned int sta, retries; | ||
1188 | int txch = tx_ring(mac)->chan.chno; | ||
1189 | |||
1190 | write_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(txch), | ||
1191 | PAS_DMA_TXCHAN_TCMDSTA_ST); | ||
1192 | |||
1193 | for (retries = 0; retries < MAX_RETRIES; retries++) { | ||
1194 | sta = read_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(txch)); | ||
1195 | if (!(sta & PAS_DMA_TXCHAN_TCMDSTA_ACT)) | ||
1196 | break; | ||
1197 | cond_resched(); | ||
1198 | } | ||
1199 | |||
1200 | if (sta & PAS_DMA_TXCHAN_TCMDSTA_ACT) | ||
1201 | dev_err(&mac->dma_pdev->dev, | ||
1202 | "Failed to stop tx channel, tcmdsta %08x\n", sta); | ||
1203 | |||
1204 | write_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(txch), 0); | ||
1205 | } | ||
1206 | |||
1207 | static void pasemi_mac_pause_rxchan(struct pasemi_mac *mac) | ||
1208 | { | ||
1209 | unsigned int sta, retries; | ||
1210 | int rxch = rx_ring(mac)->chan.chno; | ||
1211 | |||
1212 | write_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch), | ||
1213 | PAS_DMA_RXCHAN_CCMDSTA_ST); | ||
1214 | for (retries = 0; retries < MAX_RETRIES; retries++) { | ||
1215 | sta = read_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch)); | ||
1216 | if (!(sta & PAS_DMA_RXCHAN_CCMDSTA_ACT)) | ||
1217 | break; | ||
1218 | cond_resched(); | ||
1219 | } | ||
1220 | |||
1221 | if (sta & PAS_DMA_RXCHAN_CCMDSTA_ACT) | ||
1222 | dev_err(&mac->dma_pdev->dev, | ||
1223 | "Failed to stop rx channel, ccmdsta 08%x\n", sta); | ||
1224 | write_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch), 0); | ||
1225 | } | ||
1226 | |||
1227 | static void pasemi_mac_pause_rxint(struct pasemi_mac *mac) | ||
1228 | { | ||
1229 | unsigned int sta, retries; | ||
1230 | |||
1231 | write_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if), | ||
1232 | PAS_DMA_RXINT_RCMDSTA_ST); | ||
1233 | for (retries = 0; retries < MAX_RETRIES; retries++) { | ||
1234 | sta = read_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if)); | ||
1235 | if (!(sta & PAS_DMA_RXINT_RCMDSTA_ACT)) | ||
1236 | break; | ||
1237 | cond_resched(); | ||
1238 | } | ||
1239 | |||
1240 | if (sta & PAS_DMA_RXINT_RCMDSTA_ACT) | ||
1241 | dev_err(&mac->dma_pdev->dev, | ||
1242 | "Failed to stop rx interface, rcmdsta %08x\n", sta); | ||
1243 | write_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0); | ||
1244 | } | ||
1245 | |||
1178 | static int pasemi_mac_close(struct net_device *dev) | 1246 | static int pasemi_mac_close(struct net_device *dev) |
1179 | { | 1247 | { |
1180 | struct pasemi_mac *mac = netdev_priv(dev); | 1248 | struct pasemi_mac *mac = netdev_priv(dev); |
1181 | unsigned int sta; | 1249 | unsigned int sta; |
1182 | int retries; | ||
1183 | int rxch, txch; | 1250 | int rxch, txch; |
1184 | 1251 | ||
1185 | rxch = rx_ring(mac)->chan.chno; | 1252 | rxch = rx_ring(mac)->chan.chno; |
@@ -1217,51 +1284,9 @@ static int pasemi_mac_close(struct net_device *dev) | |||
1217 | pasemi_mac_clean_tx(tx_ring(mac)); | 1284 | pasemi_mac_clean_tx(tx_ring(mac)); |
1218 | pasemi_mac_clean_rx(rx_ring(mac), RX_RING_SIZE); | 1285 | pasemi_mac_clean_rx(rx_ring(mac), RX_RING_SIZE); |
1219 | 1286 | ||
1220 | /* Disable interface */ | 1287 | pasemi_mac_pause_txchan(mac); |
1221 | write_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(txch), | 1288 | pasemi_mac_pause_rxint(mac); |
1222 | PAS_DMA_TXCHAN_TCMDSTA_ST); | 1289 | pasemi_mac_pause_rxchan(mac); |
1223 | write_dma_reg( PAS_DMA_RXINT_RCMDSTA(mac->dma_if), | ||
1224 | PAS_DMA_RXINT_RCMDSTA_ST); | ||
1225 | write_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch), | ||
1226 | PAS_DMA_RXCHAN_CCMDSTA_ST); | ||
1227 | |||
1228 | for (retries = 0; retries < MAX_RETRIES; retries++) { | ||
1229 | sta = read_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(rxch)); | ||
1230 | if (!(sta & PAS_DMA_TXCHAN_TCMDSTA_ACT)) | ||
1231 | break; | ||
1232 | cond_resched(); | ||
1233 | } | ||
1234 | |||
1235 | if (sta & PAS_DMA_TXCHAN_TCMDSTA_ACT) | ||
1236 | dev_err(&mac->dma_pdev->dev, "Failed to stop tx channel\n"); | ||
1237 | |||
1238 | for (retries = 0; retries < MAX_RETRIES; retries++) { | ||
1239 | sta = read_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch)); | ||
1240 | if (!(sta & PAS_DMA_RXCHAN_CCMDSTA_ACT)) | ||
1241 | break; | ||
1242 | cond_resched(); | ||
1243 | } | ||
1244 | |||
1245 | if (sta & PAS_DMA_RXCHAN_CCMDSTA_ACT) | ||
1246 | dev_err(&mac->dma_pdev->dev, "Failed to stop rx channel\n"); | ||
1247 | |||
1248 | for (retries = 0; retries < MAX_RETRIES; retries++) { | ||
1249 | sta = read_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if)); | ||
1250 | if (!(sta & PAS_DMA_RXINT_RCMDSTA_ACT)) | ||
1251 | break; | ||
1252 | cond_resched(); | ||
1253 | } | ||
1254 | |||
1255 | if (sta & PAS_DMA_RXINT_RCMDSTA_ACT) | ||
1256 | dev_err(&mac->dma_pdev->dev, "Failed to stop rx interface\n"); | ||
1257 | |||
1258 | /* Then, disable the channel. This must be done separately from | ||
1259 | * stopping, since you can't disable when active. | ||
1260 | */ | ||
1261 | |||
1262 | write_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(txch), 0); | ||
1263 | write_dma_reg(PAS_DMA_RXCHAN_CCMDSTA(rxch), 0); | ||
1264 | write_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0); | ||
1265 | 1290 | ||
1266 | free_irq(mac->tx->chan.irq, mac->tx); | 1291 | free_irq(mac->tx->chan.irq, mac->tx); |
1267 | free_irq(mac->rx->chan.irq, mac->rx); | 1292 | free_irq(mac->rx->chan.irq, mac->rx); |
@@ -1415,6 +1440,62 @@ static int pasemi_mac_poll(struct napi_struct *napi, int budget) | |||
1415 | return pkts; | 1440 | return pkts; |
1416 | } | 1441 | } |
1417 | 1442 | ||
1443 | static int pasemi_mac_change_mtu(struct net_device *dev, int new_mtu) | ||
1444 | { | ||
1445 | struct pasemi_mac *mac = netdev_priv(dev); | ||
1446 | unsigned int reg; | ||
1447 | unsigned int rcmdsta; | ||
1448 | int running; | ||
1449 | |||
1450 | if (new_mtu < PE_MIN_MTU || new_mtu > PE_MAX_MTU) | ||
1451 | return -EINVAL; | ||
1452 | |||
1453 | running = netif_running(dev); | ||
1454 | |||
1455 | if (running) { | ||
1456 | /* Need to stop the interface, clean out all already | ||
1457 | * received buffers, free all unused buffers on the RX | ||
1458 | * interface ring, then finally re-fill the rx ring with | ||
1459 | * the new-size buffers and restart. | ||
1460 | */ | ||
1461 | |||
1462 | napi_disable(&mac->napi); | ||
1463 | netif_tx_disable(dev); | ||
1464 | pasemi_mac_intf_disable(mac); | ||
1465 | |||
1466 | rcmdsta = read_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if)); | ||
1467 | pasemi_mac_pause_rxint(mac); | ||
1468 | pasemi_mac_clean_rx(rx_ring(mac), RX_RING_SIZE); | ||
1469 | pasemi_mac_free_rx_buffers(mac); | ||
1470 | } | ||
1471 | |||
1472 | /* Change maxf, i.e. what size frames are accepted. | ||
1473 | * Need room for ethernet header and CRC word | ||
1474 | */ | ||
1475 | reg = read_mac_reg(mac, PAS_MAC_CFG_MACCFG); | ||
1476 | reg &= ~PAS_MAC_CFG_MACCFG_MAXF_M; | ||
1477 | reg |= PAS_MAC_CFG_MACCFG_MAXF(new_mtu + ETH_HLEN + 4); | ||
1478 | write_mac_reg(mac, PAS_MAC_CFG_MACCFG, reg); | ||
1479 | |||
1480 | dev->mtu = new_mtu; | ||
1481 | /* MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */ | ||
1482 | mac->bufsz = new_mtu + ETH_HLEN + ETH_FCS_LEN + LOCAL_SKB_ALIGN + 128; | ||
1483 | |||
1484 | if (running) { | ||
1485 | write_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if), | ||
1486 | rcmdsta | PAS_DMA_RXINT_RCMDSTA_EN); | ||
1487 | |||
1488 | rx_ring(mac)->next_to_fill = 0; | ||
1489 | pasemi_mac_replenish_rx_ring(dev, RX_RING_SIZE-1); | ||
1490 | |||
1491 | napi_enable(&mac->napi); | ||
1492 | netif_start_queue(dev); | ||
1493 | pasemi_mac_intf_enable(mac); | ||
1494 | } | ||
1495 | |||
1496 | return 0; | ||
1497 | } | ||
1498 | |||
1418 | static int __devinit | 1499 | static int __devinit |
1419 | pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | 1500 | pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
1420 | { | 1501 | { |
@@ -1503,6 +1584,11 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
1503 | dev->hard_start_xmit = pasemi_mac_start_tx; | 1584 | dev->hard_start_xmit = pasemi_mac_start_tx; |
1504 | dev->set_multicast_list = pasemi_mac_set_rx_mode; | 1585 | dev->set_multicast_list = pasemi_mac_set_rx_mode; |
1505 | dev->set_mac_address = pasemi_mac_set_mac_addr; | 1586 | dev->set_mac_address = pasemi_mac_set_mac_addr; |
1587 | dev->mtu = PE_DEF_MTU; | ||
1588 | /* 1500 MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */ | ||
1589 | mac->bufsz = dev->mtu + ETH_HLEN + ETH_FCS_LEN + LOCAL_SKB_ALIGN + 128; | ||
1590 | |||
1591 | dev->change_mtu = pasemi_mac_change_mtu; | ||
1506 | 1592 | ||
1507 | if (err) | 1593 | if (err) |
1508 | goto out; | 1594 | goto out; |