diff options
Diffstat (limited to 'drivers/net/ethoc.c')
| -rw-r--r-- | drivers/net/ethoc.c | 83 |
1 files changed, 56 insertions, 27 deletions
diff --git a/drivers/net/ethoc.c b/drivers/net/ethoc.c index b7311bc00258..9c950bb5e90c 100644 --- a/drivers/net/ethoc.c +++ b/drivers/net/ethoc.c | |||
| @@ -17,8 +17,13 @@ | |||
| 17 | #include <linux/mii.h> | 17 | #include <linux/mii.h> |
| 18 | #include <linux/phy.h> | 18 | #include <linux/phy.h> |
| 19 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
| 20 | #include <linux/sched.h> | ||
| 20 | #include <net/ethoc.h> | 21 | #include <net/ethoc.h> |
| 21 | 22 | ||
| 23 | static int buffer_size = 0x8000; /* 32 KBytes */ | ||
| 24 | module_param(buffer_size, int, 0); | ||
| 25 | MODULE_PARM_DESC(buffer_size, "DMA buffer allocation size"); | ||
| 26 | |||
| 22 | /* register offsets */ | 27 | /* register offsets */ |
| 23 | #define MODER 0x00 | 28 | #define MODER 0x00 |
| 24 | #define INT_SOURCE 0x04 | 29 | #define INT_SOURCE 0x04 |
| @@ -167,6 +172,7 @@ | |||
| 167 | * struct ethoc - driver-private device structure | 172 | * struct ethoc - driver-private device structure |
| 168 | * @iobase: pointer to I/O memory region | 173 | * @iobase: pointer to I/O memory region |
| 169 | * @membase: pointer to buffer memory region | 174 | * @membase: pointer to buffer memory region |
| 175 | * @dma_alloc: dma allocated buffer size | ||
| 170 | * @num_tx: number of send buffers | 176 | * @num_tx: number of send buffers |
| 171 | * @cur_tx: last send buffer written | 177 | * @cur_tx: last send buffer written |
| 172 | * @dty_tx: last buffer actually sent | 178 | * @dty_tx: last buffer actually sent |
| @@ -185,6 +191,7 @@ | |||
| 185 | struct ethoc { | 191 | struct ethoc { |
| 186 | void __iomem *iobase; | 192 | void __iomem *iobase; |
| 187 | void __iomem *membase; | 193 | void __iomem *membase; |
| 194 | int dma_alloc; | ||
| 188 | 195 | ||
| 189 | unsigned int num_tx; | 196 | unsigned int num_tx; |
| 190 | unsigned int cur_tx; | 197 | unsigned int cur_tx; |
| @@ -284,7 +291,7 @@ static int ethoc_init_ring(struct ethoc *dev) | |||
| 284 | dev->cur_rx = 0; | 291 | dev->cur_rx = 0; |
| 285 | 292 | ||
| 286 | /* setup transmission buffers */ | 293 | /* setup transmission buffers */ |
| 287 | bd.addr = 0; | 294 | bd.addr = virt_to_phys(dev->membase); |
| 288 | bd.stat = TX_BD_IRQ | TX_BD_CRC; | 295 | bd.stat = TX_BD_IRQ | TX_BD_CRC; |
| 289 | 296 | ||
| 290 | for (i = 0; i < dev->num_tx; i++) { | 297 | for (i = 0; i < dev->num_tx; i++) { |
| @@ -295,7 +302,6 @@ static int ethoc_init_ring(struct ethoc *dev) | |||
| 295 | bd.addr += ETHOC_BUFSIZ; | 302 | bd.addr += ETHOC_BUFSIZ; |
| 296 | } | 303 | } |
| 297 | 304 | ||
| 298 | bd.addr = dev->num_tx * ETHOC_BUFSIZ; | ||
| 299 | bd.stat = RX_BD_EMPTY | RX_BD_IRQ; | 305 | bd.stat = RX_BD_EMPTY | RX_BD_IRQ; |
| 300 | 306 | ||
| 301 | for (i = 0; i < dev->num_rx; i++) { | 307 | for (i = 0; i < dev->num_rx; i++) { |
| @@ -400,8 +406,12 @@ static int ethoc_rx(struct net_device *dev, int limit) | |||
| 400 | if (ethoc_update_rx_stats(priv, &bd) == 0) { | 406 | if (ethoc_update_rx_stats(priv, &bd) == 0) { |
| 401 | int size = bd.stat >> 16; | 407 | int size = bd.stat >> 16; |
| 402 | struct sk_buff *skb = netdev_alloc_skb(dev, size); | 408 | struct sk_buff *skb = netdev_alloc_skb(dev, size); |
| 409 | |||
| 410 | size -= 4; /* strip the CRC */ | ||
| 411 | skb_reserve(skb, 2); /* align TCP/IP header */ | ||
| 412 | |||
| 403 | if (likely(skb)) { | 413 | if (likely(skb)) { |
| 404 | void *src = priv->membase + bd.addr; | 414 | void *src = phys_to_virt(bd.addr); |
| 405 | memcpy_fromio(skb_put(skb, size), src, size); | 415 | memcpy_fromio(skb_put(skb, size), src, size); |
| 406 | skb->protocol = eth_type_trans(skb, dev); | 416 | skb->protocol = eth_type_trans(skb, dev); |
| 407 | priv->stats.rx_packets++; | 417 | priv->stats.rx_packets++; |
| @@ -653,9 +663,10 @@ static int ethoc_open(struct net_device *dev) | |||
| 653 | if (ret) | 663 | if (ret) |
| 654 | return ret; | 664 | return ret; |
| 655 | 665 | ||
| 656 | /* calculate the number of TX/RX buffers */ | 666 | /* calculate the number of TX/RX buffers, maximum 128 supported */ |
| 657 | num_bd = (dev->mem_end - dev->mem_start + 1) / ETHOC_BUFSIZ; | 667 | num_bd = min_t(unsigned int, |
| 658 | priv->num_tx = min(min_tx, num_bd / 4); | 668 | 128, (dev->mem_end - dev->mem_start + 1) / ETHOC_BUFSIZ); |
| 669 | priv->num_tx = max(min_tx, num_bd / 4); | ||
| 659 | priv->num_rx = num_bd - priv->num_tx; | 670 | priv->num_rx = num_bd - priv->num_tx; |
| 660 | ethoc_write(priv, TX_BD_NUM, priv->num_tx); | 671 | ethoc_write(priv, TX_BD_NUM, priv->num_tx); |
| 661 | 672 | ||
| @@ -823,7 +834,7 @@ static netdev_tx_t ethoc_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 823 | else | 834 | else |
| 824 | bd.stat &= ~TX_BD_PAD; | 835 | bd.stat &= ~TX_BD_PAD; |
| 825 | 836 | ||
| 826 | dest = priv->membase + bd.addr; | 837 | dest = phys_to_virt(bd.addr); |
| 827 | memcpy_toio(dest, skb->data, skb->len); | 838 | memcpy_toio(dest, skb->data, skb->len); |
| 828 | 839 | ||
| 829 | bd.stat &= ~(TX_BD_STATS | TX_BD_LEN_MASK); | 840 | bd.stat &= ~(TX_BD_STATS | TX_BD_LEN_MASK); |
| @@ -903,22 +914,19 @@ static int ethoc_probe(struct platform_device *pdev) | |||
| 903 | 914 | ||
| 904 | /* obtain buffer memory space */ | 915 | /* obtain buffer memory space */ |
| 905 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | 916 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); |
| 906 | if (!res) { | 917 | if (res) { |
| 907 | dev_err(&pdev->dev, "cannot obtain memory space\n"); | 918 | mem = devm_request_mem_region(&pdev->dev, res->start, |
| 908 | ret = -ENXIO; | ||
| 909 | goto free; | ||
| 910 | } | ||
| 911 | |||
| 912 | mem = devm_request_mem_region(&pdev->dev, res->start, | ||
| 913 | res->end - res->start + 1, res->name); | 919 | res->end - res->start + 1, res->name); |
| 914 | if (!mem) { | 920 | if (!mem) { |
| 915 | dev_err(&pdev->dev, "cannot request memory space\n"); | 921 | dev_err(&pdev->dev, "cannot request memory space\n"); |
| 916 | ret = -ENXIO; | 922 | ret = -ENXIO; |
| 917 | goto free; | 923 | goto free; |
| 924 | } | ||
| 925 | |||
| 926 | netdev->mem_start = mem->start; | ||
| 927 | netdev->mem_end = mem->end; | ||
| 918 | } | 928 | } |
| 919 | 929 | ||
| 920 | netdev->mem_start = mem->start; | ||
| 921 | netdev->mem_end = mem->end; | ||
| 922 | 930 | ||
| 923 | /* obtain device IRQ number */ | 931 | /* obtain device IRQ number */ |
| 924 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 932 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
| @@ -933,6 +941,7 @@ static int ethoc_probe(struct platform_device *pdev) | |||
| 933 | /* setup driver-private data */ | 941 | /* setup driver-private data */ |
| 934 | priv = netdev_priv(netdev); | 942 | priv = netdev_priv(netdev); |
| 935 | priv->netdev = netdev; | 943 | priv->netdev = netdev; |
| 944 | priv->dma_alloc = 0; | ||
| 936 | 945 | ||
| 937 | priv->iobase = devm_ioremap_nocache(&pdev->dev, netdev->base_addr, | 946 | priv->iobase = devm_ioremap_nocache(&pdev->dev, netdev->base_addr, |
| 938 | mmio->end - mmio->start + 1); | 947 | mmio->end - mmio->start + 1); |
| @@ -942,12 +951,27 @@ static int ethoc_probe(struct platform_device *pdev) | |||
| 942 | goto error; | 951 | goto error; |
| 943 | } | 952 | } |
| 944 | 953 | ||
| 945 | priv->membase = devm_ioremap_nocache(&pdev->dev, netdev->mem_start, | 954 | if (netdev->mem_end) { |
| 946 | mem->end - mem->start + 1); | 955 | priv->membase = devm_ioremap_nocache(&pdev->dev, |
| 947 | if (!priv->membase) { | 956 | netdev->mem_start, mem->end - mem->start + 1); |
| 948 | dev_err(&pdev->dev, "cannot remap memory space\n"); | 957 | if (!priv->membase) { |
| 949 | ret = -ENXIO; | 958 | dev_err(&pdev->dev, "cannot remap memory space\n"); |
| 950 | goto error; | 959 | ret = -ENXIO; |
| 960 | goto error; | ||
| 961 | } | ||
| 962 | } else { | ||
| 963 | /* Allocate buffer memory */ | ||
| 964 | priv->membase = dma_alloc_coherent(NULL, | ||
| 965 | buffer_size, (void *)&netdev->mem_start, | ||
| 966 | GFP_KERNEL); | ||
| 967 | if (!priv->membase) { | ||
| 968 | dev_err(&pdev->dev, "cannot allocate %dB buffer\n", | ||
| 969 | buffer_size); | ||
| 970 | ret = -ENOMEM; | ||
| 971 | goto error; | ||
| 972 | } | ||
| 973 | netdev->mem_end = netdev->mem_start + buffer_size; | ||
| 974 | priv->dma_alloc = buffer_size; | ||
| 951 | } | 975 | } |
| 952 | 976 | ||
| 953 | /* Allow the platform setup code to pass in a MAC address. */ | 977 | /* Allow the platform setup code to pass in a MAC address. */ |
| @@ -1034,6 +1058,9 @@ free_mdio: | |||
| 1034 | kfree(priv->mdio->irq); | 1058 | kfree(priv->mdio->irq); |
| 1035 | mdiobus_free(priv->mdio); | 1059 | mdiobus_free(priv->mdio); |
| 1036 | free: | 1060 | free: |
| 1061 | if (priv->dma_alloc) | ||
| 1062 | dma_free_coherent(NULL, priv->dma_alloc, priv->membase, | ||
| 1063 | netdev->mem_start); | ||
| 1037 | free_netdev(netdev); | 1064 | free_netdev(netdev); |
| 1038 | out: | 1065 | out: |
| 1039 | return ret; | 1066 | return ret; |
| @@ -1059,7 +1086,9 @@ static int ethoc_remove(struct platform_device *pdev) | |||
| 1059 | kfree(priv->mdio->irq); | 1086 | kfree(priv->mdio->irq); |
| 1060 | mdiobus_free(priv->mdio); | 1087 | mdiobus_free(priv->mdio); |
| 1061 | } | 1088 | } |
| 1062 | 1089 | if (priv->dma_alloc) | |
| 1090 | dma_free_coherent(NULL, priv->dma_alloc, priv->membase, | ||
| 1091 | netdev->mem_start); | ||
| 1063 | unregister_netdev(netdev); | 1092 | unregister_netdev(netdev); |
| 1064 | free_netdev(netdev); | 1093 | free_netdev(netdev); |
| 1065 | } | 1094 | } |
