From: Ian Campbell Below is a patch to support the second 32-bit DATACS chipselect in the smc91x driver to transfer data. Support is enabled by adding a resource to the platform device named 'smc91x-data32'. My platform has a 16-bit chip select for the primary IO region and no DMA. I found that throughput went from roughly 50mbit/s to 80mbit/s. I tested by throwing UDP packets at it using mgen (9000 packets/second with UDP payload of 1472 bytes is roughly 100mbit/s, I think) and counting the packets received in 60s, I then did the same for transmitting. The measurements are very rough but the improvement seems fairly significant to me. Patch was compiled for lubbock and neponset and compiled and tested on my PXA platform. Signed-off-by: Ian Campbell Signed-off-by: Nicolas Pitre Signed-off-by: Andrew Morton --- 25-akpm/arch/arm/mach-pxa/lubbock.c | 2 25-akpm/arch/arm/mach-sa1100/neponset.c | 2 25-akpm/drivers/net/smc91x.c | 150 +++++++++++++++++++++++--------- 25-akpm/drivers/net/smc91x.h | 59 +++++++++++- 4 files changed, 164 insertions(+), 49 deletions(-) diff -puN arch/arm/mach-pxa/lubbock.c~use-datacs-in-smc91x-driver arch/arm/mach-pxa/lubbock.c --- 25/arch/arm/mach-pxa/lubbock.c~use-datacs-in-smc91x-driver 2005-01-28 19:36:51.921171832 -0800 +++ 25-akpm/arch/arm/mach-pxa/lubbock.c 2005-01-28 19:36:51.930170464 -0800 @@ -137,6 +137,7 @@ static struct platform_device sa1111_dev static struct resource smc91x_resources[] = { [0] = { + .name = "smc91x-regs", .start = 0x0c000000, .end = 0x0c0fffff, .flags = IORESOURCE_MEM, @@ -147,6 +148,7 @@ static struct resource smc91x_resources[ .flags = IORESOURCE_IRQ, }, [2] = { + .name = "smc91x-attrib", .start = 0x0e000000, .end = 0x0e0fffff, .flags = IORESOURCE_MEM, diff -puN arch/arm/mach-sa1100/neponset.c~use-datacs-in-smc91x-driver arch/arm/mach-sa1100/neponset.c --- 25/arch/arm/mach-sa1100/neponset.c~use-datacs-in-smc91x-driver 2005-01-28 19:36:51.923171528 -0800 +++ 25-akpm/arch/arm/mach-sa1100/neponset.c 2005-01-28 19:36:51.930170464 -0800 @@ -266,6 +266,7 @@ static struct platform_device sa1111_dev static struct resource smc91x_resources[] = { [0] = { + .name = "smc91x-regs", .start = SA1100_CS3_PHYS, .end = SA1100_CS3_PHYS + 0x01ffffff, .flags = IORESOURCE_MEM, @@ -276,6 +277,7 @@ static struct resource smc91x_resources[ .flags = IORESOURCE_IRQ, }, [2] = { + .name = "smc91x-attrib", .start = SA1100_CS3_PHYS + 0x02000000, .end = SA1100_CS3_PHYS + 0x03ffffff, .flags = IORESOURCE_MEM, diff -puN drivers/net/smc91x.c~use-datacs-in-smc91x-driver drivers/net/smc91x.c --- 25/drivers/net/smc91x.c~use-datacs-in-smc91x-driver 2005-01-28 19:36:51.924171376 -0800 +++ 25-akpm/drivers/net/smc91x.c 2005-01-28 19:36:51.933170008 -0800 @@ -210,6 +210,10 @@ struct smc_local { spinlock_t lock; +#ifdef SMC_CAN_USE_DATACS + u32 *datacs; +#endif + #ifdef SMC_USE_PXA_DMA /* DMA needs the physical address of the chip */ u_long physaddr; @@ -2014,16 +2018,21 @@ err_out: return retval; } -static int smc_enable_device(unsigned long attrib_phys) +static int smc_enable_device(struct platform_device *pdev) { unsigned long flags; unsigned char ecor, ecsr; void *addr; + struct resource * res; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-attrib"); + if (!res) + return 0; /* * Map the attribute space. This is overkill, but clean. */ - addr = ioremap(attrib_phys, ATTRIB_SIZE); + addr = ioremap(res->start, ATTRIB_SIZE); if (!addr) return -ENOMEM; @@ -2071,6 +2080,62 @@ static int smc_enable_device(unsigned lo return 0; } +static int smc_request_attrib(struct platform_device *pdev) +{ + struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-attrib"); + + if (!res) + return 0; + + if (!request_mem_region(res->start, ATTRIB_SIZE, CARDNAME)) + return -EBUSY; + + return 0; +} + +static void smc_release_attrib(struct platform_device *pdev) +{ + struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-attrib"); + + if (res) + release_mem_region(res->start, ATTRIB_SIZE); +} + +#ifdef SMC_CAN_USE_DATACS +static void smc_request_datacs(struct platform_device *pdev, struct net_device *ndev) +{ + struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-data32"); + struct smc_local *lp = netdev_priv(ndev); + + if (!res) + return; + + if(!request_mem_region(res->start, SMC_DATA_EXTENT, CARDNAME)) { + printk(KERN_INFO "%s: failed to request datacs memory region.\n", CARDNAME); + return; + } + + lp->datacs = ioremap(res->start, SMC_DATA_EXTENT); +} + +static void smc_release_datacs(struct platform_device *pdev, struct net_device *ndev) +{ + struct smc_local *lp = netdev_priv(ndev); + struct resource * res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-data32"); + + if (lp->datacs) + iounmap(lp->datacs); + + lp->datacs = NULL; + + if (res) + release_mem_region(res->start, SMC_DATA_EXTENT); +} +#else +static void smc_request_datacs(struct platform_device *pdev, struct net_device *ndev) {} +static void smc_release_datacs(struct platform_device *pdev, struct net_device *ndev) {} +#endif + /* * smc_init(void) * Input parameters: @@ -2086,20 +2151,20 @@ static int smc_drv_probe(struct device * { struct platform_device *pdev = to_platform_device(dev); struct net_device *ndev; - struct resource *res, *ext = NULL; + struct resource *res; unsigned int *addr; int ret; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-regs"); + if (!res) + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { ret = -ENODEV; goto out; } - /* - * Request the regions. - */ - if (!request_mem_region(res->start, SMC_IO_EXTENT, "smc91x")) { + + if (!request_mem_region(res->start, SMC_IO_EXTENT, CARDNAME)) { ret = -EBUSY; goto out; } @@ -2108,7 +2173,7 @@ static int smc_drv_probe(struct device * if (!ndev) { printk("%s: could not allocate device.\n", CARDNAME); ret = -ENOMEM; - goto release_1; + goto out_release_io; } SET_MODULE_OWNER(ndev); SET_NETDEV_DEV(ndev, dev); @@ -2116,42 +2181,26 @@ static int smc_drv_probe(struct device * ndev->dma = (unsigned char)-1; ndev->irq = platform_get_irq(pdev, 0); - ext = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (ext) { - if (!request_mem_region(ext->start, ATTRIB_SIZE, ndev->name)) { - ret = -EBUSY; - goto release_1; - } - + ret = smc_request_attrib(pdev); + if (ret) + goto out_free_netdev; #if defined(CONFIG_SA1100_ASSABET) - NCR_0 |= NCR_ENET_OSC_EN; + NCR_0 |= NCR_ENET_OSC_EN; #endif - - ret = smc_enable_device(ext->start); - if (ret) - goto release_both; - } + ret = smc_enable_device(pdev); + if (ret) + goto out_release_attrib; addr = ioremap(res->start, SMC_IO_EXTENT); if (!addr) { ret = -ENOMEM; - goto release_both; + goto out_release_attrib; } dev_set_drvdata(dev, ndev); ret = smc_probe(ndev, (unsigned long)addr); - if (ret != 0) { - dev_set_drvdata(dev, NULL); - iounmap(addr); - release_both: - if (ext) - release_mem_region(ext->start, ATTRIB_SIZE); - free_netdev(ndev); - release_1: - release_mem_region(res->start, SMC_IO_EXTENT); - out: - printk("%s: not found (%d).\n", CARDNAME, ret); - } + if (ret != 0) + goto out_iounmap; #ifdef SMC_USE_PXA_DMA else { struct smc_local *lp = netdev_priv(ndev); @@ -2159,6 +2208,22 @@ static int smc_drv_probe(struct device * } #endif + smc_request_datacs(pdev, ndev); + + return 0; + + out_iounmap: + dev_set_drvdata(dev, NULL); + iounmap(addr); + out_release_attrib: + smc_release_attrib(pdev); + out_free_netdev: + free_netdev(ndev); + out_release_io: + release_mem_region(res->start, SMC_IO_EXTENT); + out: + printk("%s: not found (%d).\n", CARDNAME, ret); + return ret; } @@ -2179,10 +2244,13 @@ static int smc_drv_remove(struct device pxa_free_dma(ndev->dma); #endif iounmap((void *)ndev->base_addr); - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (res) - release_mem_region(res->start, ATTRIB_SIZE); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + smc_release_datacs(pdev,ndev); + smc_release_attrib(pdev); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "smc91x-regs"); + if (!res) + platform_get_resource(pdev, IORESOURCE_MEM, 0); release_mem_region(res->start, SMC_IO_EXTENT); free_netdev(ndev); @@ -2211,9 +2279,7 @@ static int smc_drv_resume(struct device if (ndev && level == RESUME_ENABLE) { struct smc_local *lp = netdev_priv(ndev); - - if (pdev->num_resources == 3) - smc_enable_device(pdev->resource[2].start); + smc_enable_device(pdev); if (netif_running(ndev)) { smc_reset(ndev); smc_enable(ndev); diff -puN drivers/net/smc91x.h~use-datacs-in-smc91x-driver drivers/net/smc91x.h --- 25/drivers/net/smc91x.h~use-datacs-in-smc91x-driver 2005-01-28 19:36:51.926171072 -0800 +++ 25-akpm/drivers/net/smc91x.h 2005-01-28 19:36:51.935169704 -0800 @@ -382,7 +382,7 @@ smc_pxa_dma_irq(int dma, void *dummy, st #define SMC_IO_SHIFT 0 #endif #define SMC_IO_EXTENT (16 << SMC_IO_SHIFT) - +#define SMC_DATA_EXTENT (4) /* . Bank Select Register: @@ -903,7 +903,7 @@ static const char * chip_ids[ 16 ] = { #endif #if SMC_CAN_USE_32BIT -#define SMC_PUSH_DATA(p, l) \ +#define _SMC_PUSH_DATA(p, l) \ do { \ char *__ptr = (p); \ int __len = (l); \ @@ -918,7 +918,7 @@ static const char * chip_ids[ 16 ] = { SMC_outw( *((u16 *)__ptr), ioaddr, DATA_REG ); \ } \ } while (0) -#define SMC_PULL_DATA(p, l) \ +#define _SMC_PULL_DATA(p, l) \ do { \ char *__ptr = (p); \ int __len = (l); \ @@ -938,11 +938,11 @@ static const char * chip_ids[ 16 ] = { SMC_insl( ioaddr, DATA_REG, __ptr, __len >> 2); \ } while (0) #elif SMC_CAN_USE_16BIT -#define SMC_PUSH_DATA(p, l) SMC_outsw( ioaddr, DATA_REG, p, (l) >> 1 ) -#define SMC_PULL_DATA(p, l) SMC_insw ( ioaddr, DATA_REG, p, (l) >> 1 ) +#define _SMC_PUSH_DATA(p, l) SMC_outsw( ioaddr, DATA_REG, p, (l) >> 1 ) +#define _SMC_PULL_DATA(p, l) SMC_insw ( ioaddr, DATA_REG, p, (l) >> 1 ) #elif SMC_CAN_USE_8BIT -#define SMC_PUSH_DATA(p, l) SMC_outsb( ioaddr, DATA_REG, p, l ) -#define SMC_PULL_DATA(p, l) SMC_insb ( ioaddr, DATA_REG, p, l ) +#define _SMC_PUSH_DATA(p, l) SMC_outsb( ioaddr, DATA_REG, p, l ) +#define _SMC_PULL_DATA(p, l) SMC_insb ( ioaddr, DATA_REG, p, l ) #endif #if ! SMC_CAN_USE_16BIT @@ -961,6 +961,51 @@ static const char * chip_ids[ 16 ] = { }) #endif +#if SMC_CAN_USE_DATACS +#define SMC_PUSH_DATA(p, l) \ + if ( lp->datacs ) { \ + unsigned char *__ptr = (p); \ + int __len = (l); \ + if (__len >= 2 && (unsigned long)__ptr & 2) { \ + __len -= 2; \ + SMC_outw( *((u16 *)__ptr), ioaddr, DATA_REG ); \ + __ptr += 2; \ + } \ + outsl(lp->datacs, __ptr, __len >> 2); \ + if (__len & 2) { \ + __ptr += (__len & ~3); \ + SMC_outw( *((u16 *)__ptr), ioaddr, DATA_REG ); \ + } \ + } else { \ + _SMC_PUSH_DATA(p, l); \ + } + +#define SMC_PULL_DATA(p, l) \ + if ( lp->datacs ) { \ + unsigned char *__ptr = (p); \ + int __len = (l); \ + if ((unsigned long)__ptr & 2) { \ + /* \ + * We want 32bit alignment here. \ + * Since some buses perform a full 32bit \ + * fetch even for 16bit data we can't use \ + * SMC_inw() here. Back both source (on chip \ + * and destination) pointers of 2 bytes. \ + */ \ + __ptr -= 2; \ + __len += 2; \ + SMC_SET_PTR( 2|PTR_READ|PTR_RCV|PTR_AUTOINC ); \ + } \ + __len += 2; \ + insl( lp->datacs, __ptr, __len >> 2); \ + } else { \ + _SMC_PULL_DATA(p, l); \ + } +#else +#define SMC_PUSH_DATA(p, l) _SMC_PUSH_DATA(p, l) +#define SMC_PULL_DATA(p, l) _SMC_PULL_DATA(p, l) +#endif + #if !defined (SMC_INTERRUPT_PREAMBLE) # define SMC_INTERRUPT_PREAMBLE #endif _