Commit ef1ea0b424d09452b27f5cb1a0c108b645cb25e0
Committed by
David S. Miller
1 parent
5cea73b0f7
Exists in
master
and in
7 other branches
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>
Showing 2 changed files with 172 additions and 72 deletions Side-by-side Diff
drivers/net/pasemi_mac.c
... | ... | @@ -62,6 +62,10 @@ |
62 | 62 | |
63 | 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 | 69 | #define DEFAULT_MSG_ENABLE \ |
66 | 70 | (NETIF_MSG_DRV | \ |
67 | 71 | NETIF_MSG_PROBE | \ |
... | ... | @@ -82,8 +86,6 @@ |
82 | 86 | & ((ring)->size - 1)) |
83 | 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 | 89 | MODULE_LICENSE("GPL"); |
88 | 90 | MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>"); |
89 | 91 | MODULE_DESCRIPTION("PA Semi PWRficient Ethernet driver"); |
... | ... | @@ -175,6 +177,24 @@ |
175 | 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 | 198 | static int pasemi_get_mac_addr(struct pasemi_mac *mac) |
179 | 199 | { |
180 | 200 | struct pci_dev *pdev = mac->pdev; |
... | ... | @@ -480,7 +500,7 @@ |
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 | 505 | struct pasemi_mac_rxring *rx = rx_ring(mac); |
486 | 506 | unsigned int i; |
487 | 507 | |
... | ... | @@ -500,8 +520,13 @@ |
500 | 520 | } |
501 | 521 | |
502 | 522 | for (i = 0; i < RX_RING_SIZE; i++) |
503 | - RX_DESC(rx, i) = 0; | |
523 | + RX_BUFF(rx, i) = 0; | |
524 | +} | |
504 | 525 | |
526 | +static void pasemi_mac_free_rx_resources(struct pasemi_mac *mac) | |
527 | +{ | |
528 | + pasemi_mac_free_rx_buffers(mac); | |
529 | + | |
505 | 530 | dma_free_coherent(&mac->dma_pdev->dev, RX_RING_SIZE * sizeof(u64), |
506 | 531 | rx_ring(mac)->buffers, rx_ring(mac)->buf_dma); |
507 | 532 | |
508 | 533 | |
... | ... | @@ -530,14 +555,14 @@ |
530 | 555 | /* Entry in use? */ |
531 | 556 | WARN_ON(*buff); |
532 | 557 | |
533 | - skb = dev_alloc_skb(BUF_SIZE); | |
558 | + skb = dev_alloc_skb(mac->bufsz); | |
534 | 559 | skb_reserve(skb, LOCAL_SKB_ALIGN); |
535 | 560 | |
536 | 561 | if (unlikely(!skb)) |
537 | 562 | break; |
538 | 563 | |
539 | 564 | dma = pci_map_single(mac->dma_pdev, skb->data, |
540 | - BUF_SIZE - LOCAL_SKB_ALIGN, | |
565 | + mac->bufsz - LOCAL_SKB_ALIGN, | |
541 | 566 | PCI_DMA_FROMDEVICE); |
542 | 567 | |
543 | 568 | if (unlikely(dma_mapping_error(dma))) { |
... | ... | @@ -547,7 +572,7 @@ |
547 | 572 | |
548 | 573 | info->skb = skb; |
549 | 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 | 576 | fill++; |
552 | 577 | } |
553 | 578 | |
... | ... | @@ -677,7 +702,7 @@ |
677 | 702 | |
678 | 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 | 706 | PCI_DMA_FROMDEVICE); |
682 | 707 | |
683 | 708 | if (macrx & XCT_MACRX_CRC) { |
... | ... | @@ -901,24 +926,6 @@ |
901 | 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 | 929 | static void pasemi_adjust_link(struct net_device *dev) |
923 | 930 | { |
924 | 931 | struct pasemi_mac *mac = netdev_priv(dev); |
925 | 932 | |
... | ... | @@ -1175,11 +1182,71 @@ |
1175 | 1182 | |
1176 | 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 | 1246 | static int pasemi_mac_close(struct net_device *dev) |
1179 | 1247 | { |
1180 | 1248 | struct pasemi_mac *mac = netdev_priv(dev); |
1181 | 1249 | unsigned int sta; |
1182 | - int retries; | |
1183 | 1250 | int rxch, txch; |
1184 | 1251 | |
1185 | 1252 | rxch = rx_ring(mac)->chan.chno; |
1186 | 1253 | |
... | ... | @@ -1217,52 +1284,10 @@ |
1217 | 1284 | pasemi_mac_clean_tx(tx_ring(mac)); |
1218 | 1285 | pasemi_mac_clean_rx(rx_ring(mac), RX_RING_SIZE); |
1219 | 1286 | |
1220 | - /* Disable interface */ | |
1221 | - write_dma_reg(PAS_DMA_TXCHAN_TCMDSTA(txch), | |
1222 | - PAS_DMA_TXCHAN_TCMDSTA_ST); | |
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); | |
1287 | + pasemi_mac_pause_txchan(mac); | |
1288 | + pasemi_mac_pause_rxint(mac); | |
1289 | + pasemi_mac_pause_rxchan(mac); | |
1227 | 1290 | |
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 | - | |
1266 | 1291 | free_irq(mac->tx->chan.irq, mac->tx); |
1267 | 1292 | free_irq(mac->rx->chan.irq, mac->rx); |
1268 | 1293 | |
... | ... | @@ -1415,6 +1440,62 @@ |
1415 | 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 | 1499 | static int __devinit |
1419 | 1500 | pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) |
1420 | 1501 | { |
... | ... | @@ -1503,6 +1584,11 @@ |
1503 | 1584 | dev->hard_start_xmit = pasemi_mac_start_tx; |
1504 | 1585 | dev->set_multicast_list = pasemi_mac_set_rx_mode; |
1505 | 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 | 1593 | if (err) |
1508 | 1594 | goto out; |
drivers/net/pasemi_mac.h
... | ... | @@ -59,6 +59,7 @@ |
59 | 59 | struct phy_device *phydev; |
60 | 60 | struct napi_struct napi; |
61 | 61 | |
62 | + int bufsz; /* RX ring buffer size */ | |
62 | 63 | u8 type; |
63 | 64 | #define MAC_TYPE_GMAC 1 |
64 | 65 | #define MAC_TYPE_XAUI 2 |
... | ... | @@ -96,6 +97,7 @@ |
96 | 97 | /* MAC CFG register offsets */ |
97 | 98 | enum { |
98 | 99 | PAS_MAC_CFG_PCFG = 0x80, |
100 | + PAS_MAC_CFG_MACCFG = 0x84, | |
99 | 101 | PAS_MAC_CFG_ADR0 = 0x8c, |
100 | 102 | PAS_MAC_CFG_ADR1 = 0x90, |
101 | 103 | PAS_MAC_CFG_TXP = 0x98, |
... | ... | @@ -132,6 +134,18 @@ |
132 | 134 | #define PAS_MAC_CFG_PCFG_SPD_100M 0x00000001 |
133 | 135 | #define PAS_MAC_CFG_PCFG_SPD_1G 0x00000002 |
134 | 136 | #define PAS_MAC_CFG_PCFG_SPD_10G 0x00000003 |
137 | + | |
138 | +#define PAS_MAC_CFG_MACCFG_TXT_M 0x70000000 | |
139 | +#define PAS_MAC_CFG_MACCFG_TXT_S 28 | |
140 | +#define PAS_MAC_CFG_MACCFG_PRES_M 0x0f000000 | |
141 | +#define PAS_MAC_CFG_MACCFG_PRES_S 24 | |
142 | +#define PAS_MAC_CFG_MACCFG_MAXF_M 0x00ffff00 | |
143 | +#define PAS_MAC_CFG_MACCFG_MAXF_S 8 | |
144 | +#define PAS_MAC_CFG_MACCFG_MAXF(x) (((x) << PAS_MAC_CFG_MACCFG_MAXF_S) & \ | |
145 | + PAS_MAC_CFG_MACCFG_MAXF_M) | |
146 | +#define PAS_MAC_CFG_MACCFG_MINF_M 0x000000ff | |
147 | +#define PAS_MAC_CFG_MACCFG_MINF_S 0 | |
148 | + | |
135 | 149 | #define PAS_MAC_CFG_TXP_FCF 0x01000000 |
136 | 150 | #define PAS_MAC_CFG_TXP_FCE 0x00800000 |
137 | 151 | #define PAS_MAC_CFG_TXP_FC 0x00400000 |