瀏覽代碼

ethoc: use system memory as buffer

This patch enabled the ethoc to allocate system memory as buffer
when there is no dedicated buffer memory.

Some hardware designs may not have dedicated buffer memory such as
on chip or off chip SRAM. In this case, only one memory resource is
supplied in the platform data instead of two. Then a DMA buffer can
be allocated from system memory and used for the transfer.

Signed-off-by: Thomas Chou <thomas@wytron.com.tw>
Signed-off-by: David S. Miller <davem@davemloft.net>
Thomas Chou 15 年之前
父節點
當前提交
0baa080c75
共有 1 個文件被更改,包括 44 次插入20 次删除
  1. 44 20
      drivers/net/ethoc.c

+ 44 - 20
drivers/net/ethoc.c

@@ -19,6 +19,10 @@
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <net/ethoc.h>
 #include <net/ethoc.h>
 
 
+static int buffer_size = 0x8000; /* 32 KBytes */
+module_param(buffer_size, int, 0);
+MODULE_PARM_DESC(buffer_size, "DMA buffer allocation size");
+
 /* register offsets */
 /* register offsets */
 #define	MODER		0x00
 #define	MODER		0x00
 #define	INT_SOURCE	0x04
 #define	INT_SOURCE	0x04
@@ -167,6 +171,7 @@
  * struct ethoc - driver-private device structure
  * struct ethoc - driver-private device structure
  * @iobase:	pointer to I/O memory region
  * @iobase:	pointer to I/O memory region
  * @membase:	pointer to buffer memory region
  * @membase:	pointer to buffer memory region
+ * @dma_alloc:	dma allocated buffer size
  * @num_tx:	number of send buffers
  * @num_tx:	number of send buffers
  * @cur_tx:	last send buffer written
  * @cur_tx:	last send buffer written
  * @dty_tx:	last buffer actually sent
  * @dty_tx:	last buffer actually sent
@@ -185,6 +190,7 @@
 struct ethoc {
 struct ethoc {
 	void __iomem *iobase;
 	void __iomem *iobase;
 	void __iomem *membase;
 	void __iomem *membase;
+	int dma_alloc;
 
 
 	unsigned int num_tx;
 	unsigned int num_tx;
 	unsigned int cur_tx;
 	unsigned int cur_tx;
@@ -906,22 +912,19 @@ static int ethoc_probe(struct platform_device *pdev)
 
 
 	/* obtain buffer memory space */
 	/* obtain buffer memory space */
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-	if (!res) {
-		dev_err(&pdev->dev, "cannot obtain memory space\n");
-		ret = -ENXIO;
-		goto free;
-	}
-
-	mem = devm_request_mem_region(&pdev->dev, res->start,
+	if (res) {
+		mem = devm_request_mem_region(&pdev->dev, res->start,
 			res->end - res->start + 1, res->name);
 			res->end - res->start + 1, res->name);
-	if (!mem) {
-		dev_err(&pdev->dev, "cannot request memory space\n");
-		ret = -ENXIO;
-		goto free;
+		if (!mem) {
+			dev_err(&pdev->dev, "cannot request memory space\n");
+			ret = -ENXIO;
+			goto free;
+		}
+
+		netdev->mem_start = mem->start;
+		netdev->mem_end   = mem->end;
 	}
 	}
 
 
-	netdev->mem_start = mem->start;
-	netdev->mem_end   = mem->end;
 
 
 	/* obtain device IRQ number */
 	/* obtain device IRQ number */
 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
@@ -936,6 +939,7 @@ static int ethoc_probe(struct platform_device *pdev)
 	/* setup driver-private data */
 	/* setup driver-private data */
 	priv = netdev_priv(netdev);
 	priv = netdev_priv(netdev);
 	priv->netdev = netdev;
 	priv->netdev = netdev;
+	priv->dma_alloc = 0;
 
 
 	priv->iobase = devm_ioremap_nocache(&pdev->dev, netdev->base_addr,
 	priv->iobase = devm_ioremap_nocache(&pdev->dev, netdev->base_addr,
 			mmio->end - mmio->start + 1);
 			mmio->end - mmio->start + 1);
@@ -945,12 +949,27 @@ static int ethoc_probe(struct platform_device *pdev)
 		goto error;
 		goto error;
 	}
 	}
 
 
-	priv->membase = devm_ioremap_nocache(&pdev->dev, netdev->mem_start,
-			mem->end - mem->start + 1);
-	if (!priv->membase) {
-		dev_err(&pdev->dev, "cannot remap memory space\n");
-		ret = -ENXIO;
-		goto error;
+	if (netdev->mem_end) {
+		priv->membase = devm_ioremap_nocache(&pdev->dev,
+			netdev->mem_start, mem->end - mem->start + 1);
+		if (!priv->membase) {
+			dev_err(&pdev->dev, "cannot remap memory space\n");
+			ret = -ENXIO;
+			goto error;
+		}
+	} else {
+		/* Allocate buffer memory */
+		priv->membase = dma_alloc_coherent(NULL,
+			buffer_size, (void *)&netdev->mem_start,
+			GFP_KERNEL);
+		if (!priv->membase) {
+			dev_err(&pdev->dev, "cannot allocate %dB buffer\n",
+				buffer_size);
+			ret = -ENOMEM;
+			goto error;
+		}
+		netdev->mem_end = netdev->mem_start + buffer_size;
+		priv->dma_alloc = buffer_size;
 	}
 	}
 
 
 	/* Allow the platform setup code to pass in a MAC address. */
 	/* Allow the platform setup code to pass in a MAC address. */
@@ -1037,6 +1056,9 @@ free_mdio:
 	kfree(priv->mdio->irq);
 	kfree(priv->mdio->irq);
 	mdiobus_free(priv->mdio);
 	mdiobus_free(priv->mdio);
 free:
 free:
+	if (priv->dma_alloc)
+		dma_free_coherent(NULL, priv->dma_alloc, priv->membase,
+			netdev->mem_start);
 	free_netdev(netdev);
 	free_netdev(netdev);
 out:
 out:
 	return ret;
 	return ret;
@@ -1062,7 +1084,9 @@ static int ethoc_remove(struct platform_device *pdev)
 			kfree(priv->mdio->irq);
 			kfree(priv->mdio->irq);
 			mdiobus_free(priv->mdio);
 			mdiobus_free(priv->mdio);
 		}
 		}
-
+		if (priv->dma_alloc)
+			dma_free_coherent(NULL, priv->dma_alloc, priv->membase,
+				netdev->mem_start);
 		unregister_netdev(netdev);
 		unregister_netdev(netdev);
 		free_netdev(netdev);
 		free_netdev(netdev);
 	}
 	}