This patch series adds support for the Individual Computers X-Surf 100 network card for m68k Amiga, a network adapter based on the AX88796 chip set. The driver was originally written for kernel version 3.19 by Michael Karcher (see CC:), and adapted to 4.16 for submission to netdev by me. Questions regarding motivation for some of the changes are probably best directed at Michael Karcher. The driver has been tested by Adrian <glaubitz@physik.fu-berlin.de> who will send his Tested-by tag separately. A few changes to the ax88796 driver were required: - to read the MAC address, some setup of the ax99796 chip must be done, - attach to the MII bus only on device open to allow module unloading, - allow to supersede ax_block_input/ax_block_output by card-specific optimized code, - use an optional interrupt status callback to allow easier sharing of the card interrupt, - set IRQF_SHARED if platform IRQ resource is marked shareable, - add a dummy control register write to MII reset code so back-to-back reset requests work. Some additional cleanup: - do not attempt to free IRQ in ax_remove (complements 82533ad9a1c), - unregister and free mdiobus resources in ax_mii_init error path, - clear platform drvdata on probe fail and module remove. The patch series, in order: 01/10 net: ax88796: Fix MAC address reading 02/10 net: ax88796: Attach MII bus only when open 03/10 net: ax88796: Do not free IRQ in ax_remove() (already freed in ax_close()). 04/10 net: ax88796: Add block_input/output hooks to ax_plat_data 05/10 net: ax88796: add interrupt status callback to platform data 06/10 net: ax88796: set IRQF_SHARED flag when IRQ resource is marked as shareable 07/10 net: ax88796: unregister mdiobus on ax_mii_init() fail 08/10 net: ax88796: Make reset more robust on AX88796B 09/10 net: ax88796: release platform device drvdata on probe error and module remove 10/10 net: New ax88796 platform driver for Amiga X-Surf 100 Zorro board (m68k) drivers/net/ethernet/8390/Kconfig | 14 +- drivers/net/ethernet/8390/Makefile | 1 + drivers/net/ethernet/8390/ax88796.c | 66 +++++- drivers/net/ethernet/8390/xsurf100.c | 411 ++++++++++++++++++++++++++++++++++ include/net/ax88796.h | 14 +- 5 files changed, 495 insertions(+), 11 deletions(-) Cheers, Michael Schmitz
From: Michael Karcher <debian@mkarcher.dialup.fu-berlin.de> To read the MAC address from the (virtual) SAprom, the remote DMA unit needs to be set up like for every other process access to card-local memory. Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> --- drivers/net/ethernet/8390/ax88796.c | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index 2455547..2a256aa 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -671,10 +671,16 @@ static int ax_init_dev(struct net_device *dev) if (ax->plat->flags & AXFLG_HAS_EEPROM) { unsigned char SA_prom[32]; + ei_outb(6, ioaddr + EN0_RCNTLO); + ei_outb(0, ioaddr + EN0_RCNTHI); + ei_outb(0, ioaddr + EN0_RSARLO); + ei_outb(0, ioaddr + EN0_RSARHI); + ei_outb(E8390_RREAD + E8390_START, ioaddr + NE_CMD); for (i = 0; i < sizeof(SA_prom); i += 2) { SA_prom[i] = ei_inb(ioaddr + NE_DATAPORT); SA_prom[i + 1] = ei_inb(ioaddr + NE_DATAPORT); } + ei_outb(ENISR_RDC, ioaddr + EN0_ISR); /* Ack intr. */ if (ax->plat->wordlength == 2) for (i = 0; i < 16; i++) -- 1.7.0.4
From: Michael Karcher <debian@mkarcher.dialup.fu-berlin.de> Call ax_mii_init in ax_open(), and unregister/remove mdiobus resources in ax_close(). This is needed to be able to unload the module, as the module is busy while the MII bus is attached. Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> --- drivers/net/ethernet/8390/ax88796.c | 13 +++++++++---- 1 files changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index 2a256aa..f7b8911 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -79,6 +79,8 @@ static u32 ax_msg_enable; +static int ax_mii_init(struct net_device *dev); + /* device private data */ struct ax_device { @@ -396,6 +398,10 @@ static int ax_open(struct net_device *dev) netdev_dbg(dev, "open\n"); + ret = ax_mii_init(dev); + if (ret) + goto failed_request_irq; + ret = request_irq(dev->irq, ax_ei_interrupt, ax->irqflags, dev->name, dev); if (ret) @@ -442,6 +448,9 @@ static int ax_close(struct net_device *dev) phy_disconnect(dev->phydev); free_irq(dev->irq, dev); + + mdiobus_unregister(ax->mii_bus); + free_mdio_bitbang(ax->mii_bus); return 0; } @@ -758,10 +767,6 @@ static int ax_init_dev(struct net_device *dev) dev->netdev_ops = &ax_netdev_ops; dev->ethtool_ops = &ax_ethtool_ops; - ret = ax_mii_init(dev); - if (ret) - goto err_out; - ax_NS8390_init(dev, 0); ret = register_netdev(dev); -- 1.7.0.4
From: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> This complements the fix in 82533ad9a1c that removed the free_irq call in the error path of probe, to also not call free_irq when remove is called to revert the effects of probe. Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> --- drivers/net/ethernet/8390/ax88796.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index f7b8911..a4f23ba 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -791,7 +791,6 @@ static int ax_remove(struct platform_device *pdev) struct resource *mem; unregister_netdev(dev); - free_irq(dev->irq, dev); iounmap(ei_local->mem); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- 1.7.0.4
Add platform specific hooks for block transfer reads/writes of packet buffer data, superseding the default provided ax_block_input/output. Currently used for m68k Amiga XSurf100. Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> --- drivers/net/ethernet/8390/ax88796.c | 10 ++++++++-- include/net/ax88796.h | 9 ++++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index a4f23ba..9159235 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -758,8 +758,14 @@ static int ax_init_dev(struct net_device *dev) #endif ei_local->reset_8390 = &ax_reset_8390; - ei_local->block_input = &ax_block_input; - ei_local->block_output = &ax_block_output; + if (ax->plat->block_input) + ei_local->block_input = ax->plat->block_input; + else + ei_local->block_input = &ax_block_input; + if (ax->plat->block_output) + ei_local->block_output = ax->plat->block_output; + else + ei_local->block_output = &ax_block_output; ei_local->get_8390_hdr = &ax_get_8390_hdr; ei_local->priv = 0; ei_local->msg_enable = ax_msg_enable; diff --git a/include/net/ax88796.h b/include/net/ax88796.h index b9a3bec..26cc459 100644 --- a/include/net/ax88796.h +++ b/include/net/ax88796.h @@ -8,10 +8,11 @@ * published by the Free Software Foundation. * */ - #ifndef __NET_AX88796_PLAT_H #define __NET_AX88796_PLAT_H +struct net_device; + #define AXFLG_HAS_EEPROM (1<<0) #define AXFLG_MAC_FROMDEV (1<<1) /* device already has MAC */ #define AXFLG_HAS_93CX6 (1<<2) /* use eeprom_93cx6 driver */ @@ -26,6 +27,12 @@ struct ax_plat_data { u32 *reg_offsets; /* register offsets */ u8 *mac_addr; /* MAC addr (only used when AXFLG_MAC_FROMPLATFORM is used */ + + /* uses default ax88796 buffer if set to NULL */ + void (*block_output)(struct net_device *dev, int count, + const unsigned char *buf, int star_page); + void (*block_input)(struct net_device *dev, int count, + struct sk_buff *skb, int ring_offset); }; #endif /* __NET_AX88796_PLAT_H */ -- 1.7.0.4
To be able to tell the ax88796 driver whether it is sensible to enter the 8390 interrupt handler, an "is this interrupt caused by the 88796" callback has been added to the ax_plat_data structure (with NULL being compatible to the previous behaviour). Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> --- drivers/net/ethernet/8390/ax88796.c | 23 +++++++++++++++++++++-- include/net/ax88796.h | 5 +++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index 9159235..b6d5bec 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -167,6 +167,21 @@ static void ax_reset_8390(struct net_device *dev) ei_outb(ENISR_RESET, addr + EN0_ISR); /* Ack intr. */ } +/* Wrapper for __ei_interrupt for platforms that have a platform-specific + * way to find out whether the interrupt request might be caused by + * the ax88796 chip. + */ +static irqreturn_t ax_ei_interrupt_filtered(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct ax_device *ax = to_ax_dev(dev); + struct platform_device *pdev = to_platform_device(dev->dev.parent); + + if (!ax->plat->check_irq(pdev)) + return IRQ_NONE; + + return ax_ei_interrupt(irq, dev_id); +} static void ax_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page) @@ -402,8 +417,12 @@ static int ax_open(struct net_device *dev) if (ret) goto failed_request_irq; - ret = request_irq(dev->irq, ax_ei_interrupt, ax->irqflags, - dev->name, dev); + if (ax->plat->check_irq) + ret = request_irq(dev->irq, ax_ei_interrupt_filtered, + ax->irqflags, dev->name, dev); + else + ret = request_irq(dev->irq, ax_ei_interrupt, ax->irqflags, + dev->name, dev); if (ret) goto failed_request_irq; diff --git a/include/net/ax88796.h b/include/net/ax88796.h index 26cc459..26412cd 100644 --- a/include/net/ax88796.h +++ b/include/net/ax88796.h @@ -12,6 +12,7 @@ #define __NET_AX88796_PLAT_H struct net_device; +struct platform_device; #define AXFLG_HAS_EEPROM (1<<0) #define AXFLG_MAC_FROMDEV (1<<1) /* device already has MAC */ @@ -33,6 +34,10 @@ struct ax_plat_data { const unsigned char *buf, int star_page); void (*block_input)(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset); + /* returns nonzero if a pending interrupt request might by caused by + * the ax88786. Handles all interrupts if set to NULL + */ + int (*check_irq)(struct platform_device *pdev); }; #endif /* __NET_AX88796_PLAT_H */ -- 1.7.0.4
From: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> On the Amiga X-Surf100, the network card interrupt is shared with many other interrupt sources, so requires the IRQF_SHARED flag to register. Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> --- drivers/net/ethernet/8390/ax88796.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index b6d5bec..b09cdc6 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -873,6 +873,9 @@ static int ax_probe(struct platform_device *pdev) dev->irq = irq->start; ax->irqflags = irq->flags & IRQF_TRIGGER_MASK; + if (irq->flags & IORESOURCE_IRQ_SHAREABLE) + ax->irqflags |= IRQF_SHARED; + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) { dev_err(&pdev->dev, "no MEM specified\n"); -- 1.7.0.4
From: Michael Schmitz <schmitz@debian.org> Unregister and free up mdiobus resources if ax_mii_init() failed. Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> --- drivers/net/ethernet/8390/ax88796.c | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index b09cdc6..6af9aca 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -415,7 +415,7 @@ static int ax_open(struct net_device *dev) ret = ax_mii_init(dev); if (ret) - goto failed_request_irq; + goto failed_mii; if (ax->plat->check_irq) ret = request_irq(dev->irq, ax_ei_interrupt_filtered, @@ -448,6 +448,10 @@ static int ax_open(struct net_device *dev) ax_phy_switch(dev, 0); free_irq(dev->irq, dev); failed_request_irq: + /* unregister mdiobus */ + mdiobus_unregister(ax->mii_bus); + free_mdio_bitbang(ax->mii_bus); + failed_mii: return ret; } -- 1.7.0.4
From: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> The AX88796B as installed on the X-Surf-100 does not recognize a MII reset request if the previous write to the MII control register also was a reset request. So a dummy write to the control register makes the soft reset in the PHY initialization code work. Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> --- drivers/net/ethernet/8390/ax88796.c | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index 6af9aca..a2f9a09 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -374,6 +374,10 @@ static int ax_mii_probe(struct net_device *dev) return -ENODEV; } + /* write a non-reset pattern to the control register to + * re-arm the reset request detection logic (needed on AX88796B) + */ + phy_write(phy_dev, MII_BMCR, 0); ret = phy_connect_direct(dev, phy_dev, ax_handle_link_change, PHY_INTERFACE_MODE_MII); if (ret) { -- 1.7.0.4
The net device struct pointer is stored as platform device drvdata on module probe - clear the drvdata entry on probe fail there, as well as when unloading the module. Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> --- drivers/net/ethernet/8390/ax88796.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index a2f9a09..8db6592 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -835,6 +835,7 @@ static int ax_remove(struct platform_device *pdev) release_mem_region(mem->start, resource_size(mem)); } + platform_set_drvdata(pdev, NULL); free_netdev(dev); return 0; @@ -968,6 +969,7 @@ static int ax_probe(struct platform_device *pdev) release_mem_region(mem->start, mem_size); exit_mem: + platform_set_drvdata(pdev, NULL); free_netdev(dev); return ret; -- 1.7.0.4
Add platform device driver to populate the ax88796 platform data from information provided by the XSurf100 zorro device driver. This driver will have to be loaded before loading the ax88796 module, or compiled as built-in. Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> --- drivers/net/ethernet/8390/Kconfig | 14 +- drivers/net/ethernet/8390/Makefile | 1 + drivers/net/ethernet/8390/xsurf100.c | 411 ++++++++++++++++++++++++++++++++++ 3 files changed, 425 insertions(+), 1 deletions(-) create mode 100644 drivers/net/ethernet/8390/xsurf100.c diff --git a/drivers/net/ethernet/8390/Kconfig b/drivers/net/ethernet/8390/Kconfig index fdc6734..0cadd45 100644 --- a/drivers/net/ethernet/8390/Kconfig +++ b/drivers/net/ethernet/8390/Kconfig @@ -30,7 +30,7 @@ config PCMCIA_AXNET config AX88796 tristate "ASIX AX88796 NE2000 clone support" - depends on (ARM || MIPS || SUPERH) + depends on (ARM || MIPS || SUPERH || AMIGA) select CRC32 select PHYLIB select MDIO_BITBANG @@ -45,6 +45,18 @@ config AX88796_93CX6 ---help--- Select this if your platform comes with an external 93CX6 eeprom. +config XSURF100 + tristate "Amiga XSurf 100 AX88796/NE2000 clone support" + depends on ZORRO + depends on AX88796 + ---help--- + This driver is for the Individual Computers X-Surf 100 Ethernet + card (based on the Asix AX88796 chip). If you have such a card, + say Y. Otherwise, say N. + + To compile this driver as a module, choose M here: the module + will be called xsurf100. + config HYDRA tristate "Hydra support" depends on ZORRO diff --git a/drivers/net/ethernet/8390/Makefile b/drivers/net/ethernet/8390/Makefile index f975c2f..3715f8d 100644 --- a/drivers/net/ethernet/8390/Makefile +++ b/drivers/net/ethernet/8390/Makefile @@ -16,4 +16,5 @@ obj-$(CONFIG_PCMCIA_PCNET) += pcnet_cs.o 8390.o obj-$(CONFIG_STNIC) += stnic.o 8390.o obj-$(CONFIG_ULTRA) += smc-ultra.o 8390.o obj-$(CONFIG_WD80x3) += wd.o 8390.o +obj-$(CONFIG_XSURF100) += xsurf100.o obj-$(CONFIG_ZORRO8390) += zorro8390.o 8390.o diff --git a/drivers/net/ethernet/8390/xsurf100.c b/drivers/net/ethernet/8390/xsurf100.c new file mode 100644 index 0000000..3caece0 --- /dev/null +++ b/drivers/net/ethernet/8390/xsurf100.c @@ -0,0 +1,411 @@ +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/platform_device.h> +#include <linux/zorro.h> +#include <net/ax88796.h> +#include <asm/amigaints.h> + +#define ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF100 \ + ZORRO_ID(INDIVIDUAL_COMPUTERS, 0x64, 0) + +#define XS100_IRQSTATUS_BASE 0x40 +#define XS100_8390_BASE 0x800 + +/* Longword-access area. Translated to 2 16-bit access cycles by the + * X-Surf 100 FPGA + */ +#define XS100_8390_DATA32_BASE 0x8000 +#define XS100_8390_DATA32_SIZE 0x2000 +/* Sub-Areas for fast data register access; addresses relative to area begin */ +#define XS100_8390_DATA_READ32_BASE 0x0880 +#define XS100_8390_DATA_WRITE32_BASE 0x0C80 +#define XS100_8390_DATA_AREA_SIZE 0x80 + +#define __NS8390_init ax_NS8390_init + +/* force unsigned long back to 'void __iomem *' */ +#define ax_convert_addr(_a) ((void __force __iomem *)(_a)) + +#define ei_inb(_a) z_readb(ax_convert_addr(_a)) +#define ei_outb(_v, _a) z_writeb(_v, ax_convert_addr(_a)) + +#define ei_inw(_a) z_readw(ax_convert_addr(_a)) +#define ei_outw(_v, _a) z_writew(_v, ax_convert_addr(_a)) + +#define ei_inb_p(_a) ei_inb(_a) +#define ei_outb_p(_v, _a) ei_outb(_v, _a) + +/* define EI_SHIFT() to take into account our register offsets */ +#define EI_SHIFT(x) (ei_local->reg_offset[(x)]) + +/* Ensure we have our RCR base value */ +#define AX88796_PLATFORM + +static unsigned char version[] = + "ax88796.c: Copyright 2005,2007 Simtec Electronics\n"; + +#include "lib8390.c" + +/* from ne.c */ +#define NE_CMD EI_SHIFT(0x00) +#define NE_RESET EI_SHIFT(0x1f) +#define NE_DATAPORT EI_SHIFT(0x10) + +/* Hard reset the card. This used to pause for the same period that a + * 8390 reset command required, but that shouldn't be necessary. + */ +static void ax_reset_8390(struct net_device *dev) +{ + struct ei_device *ei_local = netdev_priv(dev); + unsigned long reset_start_time = jiffies; + void __iomem *addr = (void __iomem *)dev->base_addr; + + netif_dbg(ei_local, hw, dev, "resetting the 8390 t=%ld...\n", jiffies); + + ei_outb(ei_inb(addr + NE_RESET), addr + NE_RESET); + + ei_local->txing = 0; + ei_local->dmaing = 0; + + /* This check _should_not_ be necessary, omit eventually. */ + while ((ei_inb(addr + EN0_ISR) & ENISR_RESET) == 0) { + if (time_after(jiffies, reset_start_time + 2 * HZ / 100)) { + netdev_warn(dev, "%s: did not complete.\n", __func__); + break; + } + } + + ei_outb(ENISR_RESET, addr + EN0_ISR); /* Ack intr. */ +} + +struct xsurf100_ax_plat_data { + struct ax_plat_data ax; + void __iomem *base_regs; + void __iomem *data_area; +}; + +static int is_xsurf100_network_irq(struct platform_device *pdev) +{ + struct xsurf100_ax_plat_data *xs100 = dev_get_platdata(&pdev->dev); + + return (readw(xs100->base_regs + XS100_IRQSTATUS_BASE) & 0xaaaa) != 0; +} + +/* These functions guarantee that the iomem is accessed with 32 bit + * cycles only. z_memcpy_fromio / z_memcpy_toio don't + */ +static void z_memcpy_fromio32(void *dst, const void __iomem *src, size_t bytes) +{ + while (bytes > 32) { + asm __volatile__ + ("movem.l (%0)+,%%d0-%%d7\n" + "movem.l %%d0-%%d7,(%1)\n" + "adda.l #32,%1" : "=a"(src), "=a"(dst) + : "0"(src), "1"(dst) : "d0", "d1", "d2", "d3", "d4", + "d5", "d6", "d7", "memory"); + bytes -= 32; + } + while (bytes) { + *(uint32_t *)dst = z_readl(src); + src += 4; + dst += 4; + bytes -= 4; + } +} + +static void z_memcpy_toio32(void __iomem *dst, const void *src, size_t bytes) +{ + while (bytes) { + z_writel(*(const uint32_t *)src, dst); + src += 4; + dst += 4; + bytes -= 4; + } +} + +static void xs100_write(struct net_device *dev, const void *src, + unsigned int count) +{ + struct ei_device *ei_local = netdev_priv(dev); + struct platform_device *pdev = to_platform_device(dev->dev.parent); + struct xsurf100_ax_plat_data *xs100 = dev_get_platdata(&pdev->dev); + + /* copy whole blocks */ + while (count > XS100_8390_DATA_AREA_SIZE) { + z_memcpy_toio32(xs100->data_area + + XS100_8390_DATA_WRITE32_BASE, src, + XS100_8390_DATA_AREA_SIZE); + src += XS100_8390_DATA_AREA_SIZE; + count -= XS100_8390_DATA_AREA_SIZE; + } + /* copy whole dwords */ + z_memcpy_toio32(xs100->data_area + XS100_8390_DATA_WRITE32_BASE, + src, count & ~3); + src += count & ~3; + if (count & 2) { + ei_outw(*(uint16_t *)src, ei_local->mem + NE_DATAPORT); + src += 2; + } + if (count & 1) + ei_outb(*(uint8_t *)src, ei_local->mem + NE_DATAPORT); +} + +static void xs100_read(struct net_device *dev, void *dst, unsigned int count) +{ + struct ei_device *ei_local = netdev_priv(dev); + struct platform_device *pdev = to_platform_device(dev->dev.parent); + struct xsurf100_ax_plat_data *xs100 = dev_get_platdata(&pdev->dev); + + /* copy whole blocks */ + while (count > XS100_8390_DATA_AREA_SIZE) { + z_memcpy_fromio32(dst, xs100->data_area + + XS100_8390_DATA_READ32_BASE, + XS100_8390_DATA_AREA_SIZE); + dst += XS100_8390_DATA_AREA_SIZE; + count -= XS100_8390_DATA_AREA_SIZE; + } + /* copy whole dwords */ + z_memcpy_fromio32(dst, xs100->data_area + XS100_8390_DATA_READ32_BASE, + count & ~3); + dst += count & ~3; + if (count & 2) { + *(uint16_t *)dst = ei_inw(ei_local->mem + NE_DATAPORT); + dst += 2; + } + if (count & 1) + *(uint8_t *)dst = ei_inb(ei_local->mem + NE_DATAPORT); +} + +/* Block input and output, similar to the Crynwr packet driver. If + * you are porting to a new ethercard, look at the packet driver + * source for hints. The NEx000 doesn't share the on-board packet + * memory -- you have to put the packet out through the "remote DMA" + * dataport using ei_outb. + */ +static void xs100_block_input(struct net_device *dev, int count, + struct sk_buff *skb, int ring_offset) +{ + struct ei_device *ei_local = netdev_priv(dev); + void __iomem *nic_base = ei_local->mem; + char *buf = skb->data; + + if (ei_local->dmaing) { + netdev_err(dev, + "DMAing conflict in %s " + "[DMAstat:%d][irqlock:%d].\n", + __func__, + ei_local->dmaing, ei_local->irqlock); + return; + } + + ei_local->dmaing |= 0x01; + + ei_outb(E8390_NODMA + E8390_PAGE0 + E8390_START, nic_base + NE_CMD); + ei_outb(count & 0xff, nic_base + EN0_RCNTLO); + ei_outb(count >> 8, nic_base + EN0_RCNTHI); + ei_outb(ring_offset & 0xff, nic_base + EN0_RSARLO); + ei_outb(ring_offset >> 8, nic_base + EN0_RSARHI); + ei_outb(E8390_RREAD + E8390_START, nic_base + NE_CMD); + + xs100_read(dev, buf, count); + + ei_local->dmaing &= ~1; +} + +static void xs100_block_output(struct net_device *dev, int count, + const unsigned char *buf, const int start_page) +{ + struct ei_device *ei_local = netdev_priv(dev); + void __iomem *nic_base = ei_local->mem; + unsigned long dma_start; + + /* Round the count up for word writes. Do we need to do this? + * What effect will an odd byte count have on the 8390? I + * should check someday. + */ + if (ei_local->word16 && (count & 0x01)) + count++; + + /* This *shouldn't* happen. If it does, it's the last thing + * you'll see + */ + if (ei_local->dmaing) { + netdev_err(dev, "DMAing conflict in %s " + "[DMAstat:%d][irqlock:%d]\n", + __func__, + ei_local->dmaing, ei_local->irqlock); + return; + } + + ei_local->dmaing |= 0x01; + /* We should already be in page 0, but to be safe... */ + ei_outb(E8390_PAGE0 + E8390_START + E8390_NODMA, nic_base + NE_CMD); + + ei_outb(ENISR_RDC, nic_base + EN0_ISR); + + /* Now the normal output. */ + ei_outb(count & 0xff, nic_base + EN0_RCNTLO); + ei_outb(count >> 8, nic_base + EN0_RCNTHI); + ei_outb(0x00, nic_base + EN0_RSARLO); + ei_outb(start_page, nic_base + EN0_RSARHI); + + ei_outb(E8390_RWRITE + E8390_START, nic_base + NE_CMD); + + xs100_write(dev, buf, count); + + dma_start = jiffies; + + while ((ei_inb(nic_base + EN0_ISR) & ENISR_RDC) == 0) { + if (jiffies - dma_start > 2 * HZ / 100) { /* 20ms */ + netdev_warn(dev, "timeout waiting for Tx RDC.\n"); + ax_reset_8390(dev); + ax_NS8390_init(dev, 1); + break; + } + } + + ei_outb(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ + ei_local->dmaing &= ~0x01; +} + +static int xsurf100_probe(struct zorro_dev *zdev, + const struct zorro_device_id *ent) +{ + struct platform_device *pdev; + struct xsurf100_ax_plat_data ax88796_data; + struct resource res[2] = { + DEFINE_RES_NAMED(IRQ_AMIGA_PORTS, 1, NULL, + IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE), + DEFINE_RES_MEM(zdev->resource.start + XS100_8390_BASE, + 4 * 0x20) + }; + int reg; + /* This table is referenced in the device structure, so it must + * outlive the scope of xsurf100_probe. + */ + static u32 reg_offsets[32]; + int ret = 0; + + /* X-Surf 100 control and 32 bit ring buffer data access areas. + * These resources are not used by the ax88796 driver, so must + * be requested here and passed via platform data. + */ + + if (!request_mem_region(zdev->resource.start, 0x100, zdev->name)) { + dev_err(&zdev->dev, "cannot reserve X-Surf 100 control registers\n"); + return -ENXIO; + } + + if (!request_mem_region(zdev->resource.start + + XS100_8390_DATA32_BASE, + XS100_8390_DATA32_SIZE, + "X-Surf 100 32-bit data access")) { + dev_err(&zdev->dev, "cannot reserve 32-bit area\n"); + ret = -ENXIO; + goto exit_req; + } + + for (reg = 0; reg < 0x20; reg++) + reg_offsets[reg] = 4 * reg; + + memset(&ax88796_data, 0, sizeof(ax88796_data)); + ax88796_data.ax.flags = AXFLG_HAS_EEPROM; + ax88796_data.ax.wordlength = 2; + ax88796_data.ax.dcr_val = 0x48; + ax88796_data.ax.rcr_val = 0x40; + ax88796_data.ax.reg_offsets = reg_offsets; + ax88796_data.ax.check_irq = is_xsurf100_network_irq; + ax88796_data.base_regs = ioremap(zdev->resource.start, 0x100); + + /* error handling for ioremap regs */ + if (!ax88796_data.base_regs) { + dev_err(&zdev->dev, "Cannot ioremap area %p (registers)\n", + (void *)zdev->resource.start); + + ret = -ENXIO; + goto exit_req2; + } + + ax88796_data.data_area = ioremap(zdev->resource.start + + XS100_8390_DATA32_BASE, XS100_8390_DATA32_SIZE); + + /* error handling for ioremap data */ + if (!ax88796_data.data_area) { + dev_err(&zdev->dev, "Cannot ioremap area %p (32-bit access)\n", + (void *)zdev->resource.start + XS100_8390_DATA32_BASE); + + ret = -ENXIO; + goto exit_mem; + } + + ax88796_data.ax.block_output = xs100_block_output; + ax88796_data.ax.block_input = xs100_block_input; + + pdev = platform_device_register_resndata(&zdev->dev, "ax88796", + zdev->slotaddr, res, 2, + &ax88796_data, + sizeof(ax88796_data)); + + if (IS_ERR(pdev)) { + dev_err(&zdev->dev, "cannot register platform device\n"); + ret = -ENXIO; + goto exit_mem2; + } + + zorro_set_drvdata(zdev, pdev); + + if (!ret) + return 0; + + exit_mem2: + iounmap(ax88796_data.data_area); + + exit_mem: + iounmap(ax88796_data.base_regs); + + exit_req2: + release_mem_region(zdev->resource.start + XS100_8390_DATA32_BASE, + XS100_8390_DATA32_SIZE); + + exit_req: + release_mem_region(zdev->resource.start, 0x100); + + return ret; +} + +static void xsurf100_remove(struct zorro_dev *zdev) +{ + struct platform_device *pdev; + struct xsurf100_ax_plat_data *xs100; + + pdev = zorro_get_drvdata(zdev); + xs100 = dev_get_platdata(&pdev->dev); + + platform_device_unregister(pdev); + + iounmap(xs100->base_regs); + release_mem_region(zdev->resource.start, 0x100); + iounmap(xs100->data_area); + release_mem_region(zdev->resource.start + XS100_8390_DATA32_BASE, + XS100_8390_DATA32_SIZE); +} + +static const struct zorro_device_id xsurf100_zorro_tbl[] = { + { ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF100, }, + { 0 } +}; + +MODULE_DEVICE_TABLE(zorro, xsurf100_zorro_tbl); + +static struct zorro_driver xsurf100_driver = { + .name = "xsurf100", + .id_table = xsurf100_zorro_tbl, + .probe = xsurf100_probe, + .remove = xsurf100_remove, +}; + +module_driver(xsurf100_driver, zorro_register_driver, zorro_unregister_driver); + +MODULE_DESCRIPTION("X-Surf 100 driver"); +MODULE_AUTHOR("Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de>"); +MODULE_LICENSE("GPL v2"); -- 1.7.0.4
On Tue, Apr 17, 2018 at 10:04:37AM +1200, Michael Schmitz wrote: > From: Michael Karcher <debian@mkarcher.dialup.fu-berlin.de> > > Call ax_mii_init in ax_open(), and unregister/remove mdiobus resources > in ax_close(). > > This is needed to be able to unload the module, as the module is busy > while the MII bus is attached. > > Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> > Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> > --- > drivers/net/ethernet/8390/ax88796.c | 13 +++++++++---- > 1 files changed, 9 insertions(+), 4 deletions(-) > > diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c > index 2a256aa..f7b8911 100644 > --- a/drivers/net/ethernet/8390/ax88796.c > +++ b/drivers/net/ethernet/8390/ax88796.c > @@ -79,6 +79,8 @@ > > static u32 ax_msg_enable; > > +static int ax_mii_init(struct net_device *dev); Hi Michael We try to avoid forward declarations. Please can you move ax_mii_init() so this is not needed. > + > /* device private data */ > > struct ax_device { > @@ -396,6 +398,10 @@ static int ax_open(struct net_device *dev) > > netdev_dbg(dev, "open\n"); > > + ret = ax_mii_init(dev); > + if (ret) > + goto failed_request_irq; > + > ret = request_irq(dev->irq, ax_ei_interrupt, ax->irqflags, > dev->name, dev); > if (ret) You are missing some cleanup on error at the end of ax_open(). It was also missing before. Andrew
On Tue, Apr 17, 2018 at 10:04:43AM +1200, Michael Schmitz wrote:
> From: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
>
> The AX88796B as installed on the X-Surf-100 does not recognize a MII reset
> request if the previous write to the MII control register also was a reset
> request. So a dummy write to the control register makes the soft reset in
> the PHY initialization code work.
>
> Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de>
> ---
> drivers/net/ethernet/8390/ax88796.c | 4 ++++
> 1 files changed, 4 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c
> index 6af9aca..a2f9a09 100644
> --- a/drivers/net/ethernet/8390/ax88796.c
> +++ b/drivers/net/ethernet/8390/ax88796.c
> @@ -374,6 +374,10 @@ static int ax_mii_probe(struct net_device *dev)
> return -ENODEV;
> }
>
> + /* write a non-reset pattern to the control register to
> + * re-arm the reset request detection logic (needed on AX88796B)
> + */
> + phy_write(phy_dev, MII_BMCR, 0);
This should really be fixed in the PHY driver, not the MAC.
Andrew
Hi Andrew, thank you for reviewing this series! On Tue, Apr 17, 2018 at 10:59 AM, Andrew Lunn <andrew@lunn.ch> wrote: > On Tue, Apr 17, 2018 at 10:04:37AM +1200, Michael Schmitz wrote: >> From: Michael Karcher <debian@mkarcher.dialup.fu-berlin.de> >> >> Call ax_mii_init in ax_open(), and unregister/remove mdiobus resources >> in ax_close(). >> >> This is needed to be able to unload the module, as the module is busy >> while the MII bus is attached. >> >> Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> >> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> >> --- >> drivers/net/ethernet/8390/ax88796.c | 13 +++++++++---- >> 1 files changed, 9 insertions(+), 4 deletions(-) >> >> diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c >> index 2a256aa..f7b8911 100644 >> --- a/drivers/net/ethernet/8390/ax88796.c >> +++ b/drivers/net/ethernet/8390/ax88796.c >> @@ -79,6 +79,8 @@ >> >> static u32 ax_msg_enable; >> >> +static int ax_mii_init(struct net_device *dev); > > Hi Michael > > We try to avoid forward declarations. Please can you move > ax_mii_init() so this is not needed. Done that - had to move the entire bitbang stuff along with ax_mii_init() though. >> + >> /* device private data */ >> >> struct ax_device { >> @@ -396,6 +398,10 @@ static int ax_open(struct net_device *dev) >> >> netdev_dbg(dev, "open\n"); >> >> + ret = ax_mii_init(dev); >> + if (ret) >> + goto failed_request_irq; >> + >> ret = request_irq(dev->irq, ax_ei_interrupt, ax->irqflags, >> dev->name, dev); >> if (ret) > > You are missing some cleanup on error at the end of ax_open(). > It was also missing before. Yep, that's addressed in patch 7 of this series. I'll fold that into this one for clarity. Cheers, Michael > > Andrew
Hi Andrew, On Tue, Apr 17, 2018 at 11:12 AM, Andrew Lunn <andrew@lunn.ch> wrote: > On Tue, Apr 17, 2018 at 10:04:43AM +1200, Michael Schmitz wrote: >> From: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> >> >> The AX88796B as installed on the X-Surf-100 does not recognize a MII reset >> request if the previous write to the MII control register also was a reset >> request. So a dummy write to the control register makes the soft reset in >> the PHY initialization code work. >> >> Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> >> --- >> drivers/net/ethernet/8390/ax88796.c | 4 ++++ >> 1 files changed, 4 insertions(+), 0 deletions(-) >> >> diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c >> index 6af9aca..a2f9a09 100644 >> --- a/drivers/net/ethernet/8390/ax88796.c >> +++ b/drivers/net/ethernet/8390/ax88796.c >> @@ -374,6 +374,10 @@ static int ax_mii_probe(struct net_device *dev) >> return -ENODEV; >> } >> >> + /* write a non-reset pattern to the control register to >> + * re-arm the reset request detection logic (needed on AX88796B) >> + */ >> + phy_write(phy_dev, MII_BMCR, 0); > > This should really be fixed in the PHY driver, not the MAC. OK - do you want this separate, or as part of this series? Might have a few side effects on more commonly used hardware, perhaps? Cheers, Michael > > Andrew
> > This should really be fixed in the PHY driver, not the MAC.
>
> OK - do you want this separate, or as part of this series? Might have
> a few side effects on more commonly used hardware, perhaps?
Hi Michael
What PHY driver is used? In the driver you can implement a .soft_reset
function which first does the dummy write, and then uses
genphy_soft_reset() to do the actual reset.
Andrew
This patch series adds support for the Individual Computers X-Surf 100 network card for m68k Amiga, a network adapter based on the AX88796 chip set. The driver was originally written for kernel version 3.19 by Michael Karcher (see CC:), and adapted to 4.16 for submission to netdev by me. Questions regarding motivation for some of the changes are probably best directed at Michael Karcher. The driver has been tested by Adrian <glaubitz@physik.fu-berlin.de> who will send his Tested-by tag separately. A few changes to the ax88796 driver were required: - to read the MAC address, some setup of the ax99796 chip must be done, - attach to the MII bus only on device open to allow module unloading, - allow to supersede ax_block_input/ax_block_output by card-specific optimized code, - use an optional interrupt status callback to allow easier sharing of the card interrupt, - set IRQF_SHARED if platform IRQ resource is marked shareable, Some additional cleanup: - do not attempt to free IRQ in ax_remove (complements 82533ad9a1c), - clear platform drvdata on probe fail and module remove. Changes since v1: Raised in review by Andrew Lunn: - move MII code around to avoid need for forward declaration - combine patches 2 and 7 to add cleanup in error path The patch series, in order: 1/8 net: ax88796: Fix MAC address reading 2/8 net: ax88796: Attach MII bus only when open 3/8 net: ax88796: Do not free IRQ in ax_remove() (already freed in ax_close()). 4/8 net: ax88796: Add block_input/output hooks to ax_plat_data 5/8 net: ax88796: add interrupt status callback to platform data 6/8 net: ax88796: set IRQF_SHARED flag when IRQ resource is marked as shareable 7/8 net: ax88796: release platform device drvdata on probe error and module remove 8/8 net: New ax88796 platform driver for Amiga X-Surf 100 Zorro board (m68k) drivers/net/ethernet/8390/Kconfig | 14 +- drivers/net/ethernet/8390/Makefile | 1 + drivers/net/ethernet/8390/ax88796.c | 228 +++++++++++-------- drivers/net/ethernet/8390/xsurf100.c | 411 ++++++++++++++++++++++++++++++++++ include/net/ax88796.h | 14 +- 5 files changed, 573 insertions(+), 95 deletions(-) Cheers, Michael
From: Michael Karcher <debian@mkarcher.dialup.fu-berlin.de> To read the MAC address from the (virtual) SAprom, the remote DMA unit needs to be set up like for every other process access to card-local memory. Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> --- drivers/net/ethernet/8390/ax88796.c | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index 2455547..2a256aa 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -671,10 +671,16 @@ static int ax_init_dev(struct net_device *dev) if (ax->plat->flags & AXFLG_HAS_EEPROM) { unsigned char SA_prom[32]; + ei_outb(6, ioaddr + EN0_RCNTLO); + ei_outb(0, ioaddr + EN0_RCNTHI); + ei_outb(0, ioaddr + EN0_RSARLO); + ei_outb(0, ioaddr + EN0_RSARHI); + ei_outb(E8390_RREAD + E8390_START, ioaddr + NE_CMD); for (i = 0; i < sizeof(SA_prom); i += 2) { SA_prom[i] = ei_inb(ioaddr + NE_DATAPORT); SA_prom[i + 1] = ei_inb(ioaddr + NE_DATAPORT); } + ei_outb(ENISR_RDC, ioaddr + EN0_ISR); /* Ack intr. */ if (ax->plat->wordlength == 2) for (i = 0; i < 16; i++) -- 1.7.0.4
From: Michael Karcher <debian@mkarcher.dialup.fu-berlin.de> Call ax_mii_init in ax_open(), and unregister/remove mdiobus resources in ax_close(). This is needed to be able to unload the module, as the module is busy while the MII bus is attached. Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> --- drivers/net/ethernet/8390/ax88796.c | 183 ++++++++++++++++++----------------- 1 files changed, 95 insertions(+), 88 deletions(-) diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index 2a256aa..83e59ae 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -389,6 +389,90 @@ static void ax_phy_switch(struct net_device *dev, int on) ei_outb(reg_gpoc, ei_local->mem + EI_SHIFT(0x17)); } +static void ax_bb_mdc(struct mdiobb_ctrl *ctrl, int level) +{ + struct ax_device *ax = container_of(ctrl, struct ax_device, bb_ctrl); + + if (level) + ax->reg_memr |= AX_MEMR_MDC; + else + ax->reg_memr &= ~AX_MEMR_MDC; + + ei_outb(ax->reg_memr, ax->addr_memr); +} + +static void ax_bb_dir(struct mdiobb_ctrl *ctrl, int output) +{ + struct ax_device *ax = container_of(ctrl, struct ax_device, bb_ctrl); + + if (output) + ax->reg_memr &= ~AX_MEMR_MDIR; + else + ax->reg_memr |= AX_MEMR_MDIR; + + ei_outb(ax->reg_memr, ax->addr_memr); +} + +static void ax_bb_set_data(struct mdiobb_ctrl *ctrl, int value) +{ + struct ax_device *ax = container_of(ctrl, struct ax_device, bb_ctrl); + + if (value) + ax->reg_memr |= AX_MEMR_MDO; + else + ax->reg_memr &= ~AX_MEMR_MDO; + + ei_outb(ax->reg_memr, ax->addr_memr); +} + +static int ax_bb_get_data(struct mdiobb_ctrl *ctrl) +{ + struct ax_device *ax = container_of(ctrl, struct ax_device, bb_ctrl); + int reg_memr = ei_inb(ax->addr_memr); + + return reg_memr & AX_MEMR_MDI ? 1 : 0; +} + +static const struct mdiobb_ops bb_ops = { + .owner = THIS_MODULE, + .set_mdc = ax_bb_mdc, + .set_mdio_dir = ax_bb_dir, + .set_mdio_data = ax_bb_set_data, + .get_mdio_data = ax_bb_get_data, +}; + +static int ax_mii_init(struct net_device *dev) +{ + struct platform_device *pdev = to_platform_device(dev->dev.parent); + struct ei_device *ei_local = netdev_priv(dev); + struct ax_device *ax = to_ax_dev(dev); + int err; + + ax->bb_ctrl.ops = &bb_ops; + ax->addr_memr = ei_local->mem + AX_MEMR; + ax->mii_bus = alloc_mdio_bitbang(&ax->bb_ctrl); + if (!ax->mii_bus) { + err = -ENOMEM; + goto out; + } + + ax->mii_bus->name = "ax88796_mii_bus"; + ax->mii_bus->parent = dev->dev.parent; + snprintf(ax->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", + pdev->name, pdev->id); + + err = mdiobus_register(ax->mii_bus); + if (err) + goto out_free_mdio_bitbang; + + return 0; + + out_free_mdio_bitbang: + free_mdio_bitbang(ax->mii_bus); + out: + return err; +} + static int ax_open(struct net_device *dev) { struct ax_device *ax = to_ax_dev(dev); @@ -396,6 +480,10 @@ static int ax_open(struct net_device *dev) netdev_dbg(dev, "open\n"); + ret = ax_mii_init(dev); + if (ret) + goto failed_mii; + ret = request_irq(dev->irq, ax_ei_interrupt, ax->irqflags, dev->name, dev); if (ret) @@ -423,6 +511,10 @@ static int ax_open(struct net_device *dev) ax_phy_switch(dev, 0); free_irq(dev->irq, dev); failed_request_irq: + /* unregister mdiobus */ + mdiobus_unregister(ax->mii_bus); + free_mdio_bitbang(ax->mii_bus); + failed_mii: return ret; } @@ -442,6 +534,9 @@ static int ax_close(struct net_device *dev) phy_disconnect(dev->phydev); free_irq(dev->irq, dev); + + mdiobus_unregister(ax->mii_bus); + free_mdio_bitbang(ax->mii_bus); return 0; } @@ -541,92 +636,8 @@ static void ax_eeprom_register_write(struct eeprom_93cx6 *eeprom) #endif }; -static void ax_bb_mdc(struct mdiobb_ctrl *ctrl, int level) -{ - struct ax_device *ax = container_of(ctrl, struct ax_device, bb_ctrl); - - if (level) - ax->reg_memr |= AX_MEMR_MDC; - else - ax->reg_memr &= ~AX_MEMR_MDC; - - ei_outb(ax->reg_memr, ax->addr_memr); -} - -static void ax_bb_dir(struct mdiobb_ctrl *ctrl, int output) -{ - struct ax_device *ax = container_of(ctrl, struct ax_device, bb_ctrl); - - if (output) - ax->reg_memr &= ~AX_MEMR_MDIR; - else - ax->reg_memr |= AX_MEMR_MDIR; - - ei_outb(ax->reg_memr, ax->addr_memr); -} - -static void ax_bb_set_data(struct mdiobb_ctrl *ctrl, int value) -{ - struct ax_device *ax = container_of(ctrl, struct ax_device, bb_ctrl); - - if (value) - ax->reg_memr |= AX_MEMR_MDO; - else - ax->reg_memr &= ~AX_MEMR_MDO; - - ei_outb(ax->reg_memr, ax->addr_memr); -} - -static int ax_bb_get_data(struct mdiobb_ctrl *ctrl) -{ - struct ax_device *ax = container_of(ctrl, struct ax_device, bb_ctrl); - int reg_memr = ei_inb(ax->addr_memr); - - return reg_memr & AX_MEMR_MDI ? 1 : 0; -} - -static const struct mdiobb_ops bb_ops = { - .owner = THIS_MODULE, - .set_mdc = ax_bb_mdc, - .set_mdio_dir = ax_bb_dir, - .set_mdio_data = ax_bb_set_data, - .get_mdio_data = ax_bb_get_data, -}; - /* setup code */ -static int ax_mii_init(struct net_device *dev) -{ - struct platform_device *pdev = to_platform_device(dev->dev.parent); - struct ei_device *ei_local = netdev_priv(dev); - struct ax_device *ax = to_ax_dev(dev); - int err; - - ax->bb_ctrl.ops = &bb_ops; - ax->addr_memr = ei_local->mem + AX_MEMR; - ax->mii_bus = alloc_mdio_bitbang(&ax->bb_ctrl); - if (!ax->mii_bus) { - err = -ENOMEM; - goto out; - } - - ax->mii_bus->name = "ax88796_mii_bus"; - ax->mii_bus->parent = dev->dev.parent; - snprintf(ax->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", - pdev->name, pdev->id); - - err = mdiobus_register(ax->mii_bus); - if (err) - goto out_free_mdio_bitbang; - - return 0; - - out_free_mdio_bitbang: - free_mdio_bitbang(ax->mii_bus); - out: - return err; -} - static void ax_initial_setup(struct net_device *dev, struct ei_device *ei_local) { void __iomem *ioaddr = ei_local->mem; @@ -758,10 +769,6 @@ static int ax_init_dev(struct net_device *dev) dev->netdev_ops = &ax_netdev_ops; dev->ethtool_ops = &ax_ethtool_ops; - ret = ax_mii_init(dev); - if (ret) - goto err_out; - ax_NS8390_init(dev, 0); ret = register_netdev(dev); -- 1.7.0.4
From: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> This complements the fix in 82533ad9a1c that removed the free_irq call in the error path of probe, to also not call free_irq when remove is called to revert the effects of probe. Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> --- drivers/net/ethernet/8390/ax88796.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index 83e59ae..ecf104c 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -793,7 +793,6 @@ static int ax_remove(struct platform_device *pdev) struct resource *mem; unregister_netdev(dev); - free_irq(dev->irq, dev); iounmap(ei_local->mem); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- 1.7.0.4
Add platform specific hooks for block transfer reads/writes of packet buffer data, superseding the default provided ax_block_input/output. Currently used for m68k Amiga XSurf100. Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> --- drivers/net/ethernet/8390/ax88796.c | 10 ++++++++-- include/net/ax88796.h | 9 ++++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index ecf104c..29cde38 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -760,8 +760,14 @@ static int ax_init_dev(struct net_device *dev) #endif ei_local->reset_8390 = &ax_reset_8390; - ei_local->block_input = &ax_block_input; - ei_local->block_output = &ax_block_output; + if (ax->plat->block_input) + ei_local->block_input = ax->plat->block_input; + else + ei_local->block_input = &ax_block_input; + if (ax->plat->block_output) + ei_local->block_output = ax->plat->block_output; + else + ei_local->block_output = &ax_block_output; ei_local->get_8390_hdr = &ax_get_8390_hdr; ei_local->priv = 0; ei_local->msg_enable = ax_msg_enable; diff --git a/include/net/ax88796.h b/include/net/ax88796.h index b9a3bec..26cc459 100644 --- a/include/net/ax88796.h +++ b/include/net/ax88796.h @@ -8,10 +8,11 @@ * published by the Free Software Foundation. * */ - #ifndef __NET_AX88796_PLAT_H #define __NET_AX88796_PLAT_H +struct net_device; + #define AXFLG_HAS_EEPROM (1<<0) #define AXFLG_MAC_FROMDEV (1<<1) /* device already has MAC */ #define AXFLG_HAS_93CX6 (1<<2) /* use eeprom_93cx6 driver */ @@ -26,6 +27,12 @@ struct ax_plat_data { u32 *reg_offsets; /* register offsets */ u8 *mac_addr; /* MAC addr (only used when AXFLG_MAC_FROMPLATFORM is used */ + + /* uses default ax88796 buffer if set to NULL */ + void (*block_output)(struct net_device *dev, int count, + const unsigned char *buf, int star_page); + void (*block_input)(struct net_device *dev, int count, + struct sk_buff *skb, int ring_offset); }; #endif /* __NET_AX88796_PLAT_H */ -- 1.7.0.4
To be able to tell the ax88796 driver whether it is sensible to enter the 8390 interrupt handler, an "is this interrupt caused by the 88796" callback has been added to the ax_plat_data structure (with NULL being compatible to the previous behaviour). Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> --- drivers/net/ethernet/8390/ax88796.c | 23 +++++++++++++++++++++-- include/net/ax88796.h | 5 +++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index 29cde38..c799441 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -165,6 +165,21 @@ static void ax_reset_8390(struct net_device *dev) ei_outb(ENISR_RESET, addr + EN0_ISR); /* Ack intr. */ } +/* Wrapper for __ei_interrupt for platforms that have a platform-specific + * way to find out whether the interrupt request might be caused by + * the ax88796 chip. + */ +static irqreturn_t ax_ei_interrupt_filtered(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct ax_device *ax = to_ax_dev(dev); + struct platform_device *pdev = to_platform_device(dev->dev.parent); + + if (!ax->plat->check_irq(pdev)) + return IRQ_NONE; + + return ax_ei_interrupt(irq, dev_id); +} static void ax_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page) @@ -484,8 +499,12 @@ static int ax_open(struct net_device *dev) if (ret) goto failed_mii; - ret = request_irq(dev->irq, ax_ei_interrupt, ax->irqflags, - dev->name, dev); + if (ax->plat->check_irq) + ret = request_irq(dev->irq, ax_ei_interrupt_filtered, + ax->irqflags, dev->name, dev); + else + ret = request_irq(dev->irq, ax_ei_interrupt, ax->irqflags, + dev->name, dev); if (ret) goto failed_request_irq; diff --git a/include/net/ax88796.h b/include/net/ax88796.h index 26cc459..26412cd 100644 --- a/include/net/ax88796.h +++ b/include/net/ax88796.h @@ -12,6 +12,7 @@ #define __NET_AX88796_PLAT_H struct net_device; +struct platform_device; #define AXFLG_HAS_EEPROM (1<<0) #define AXFLG_MAC_FROMDEV (1<<1) /* device already has MAC */ @@ -33,6 +34,10 @@ struct ax_plat_data { const unsigned char *buf, int star_page); void (*block_input)(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset); + /* returns nonzero if a pending interrupt request might by caused by + * the ax88786. Handles all interrupts if set to NULL + */ + int (*check_irq)(struct platform_device *pdev); }; #endif /* __NET_AX88796_PLAT_H */ -- 1.7.0.4
From: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> On the Amiga X-Surf100, the network card interrupt is shared with many other interrupt sources, so requires the IRQF_SHARED flag to register. Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> --- drivers/net/ethernet/8390/ax88796.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index c799441..a72dfbc 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -875,6 +875,9 @@ static int ax_probe(struct platform_device *pdev) dev->irq = irq->start; ax->irqflags = irq->flags & IRQF_TRIGGER_MASK; + if (irq->flags & IORESOURCE_IRQ_SHAREABLE) + ax->irqflags |= IRQF_SHARED; + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) { dev_err(&pdev->dev, "no MEM specified\n"); -- 1.7.0.4
The net device struct pointer is stored as platform device drvdata on module probe - clear the drvdata entry on probe fail there, as well as when unloading the module. Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> --- drivers/net/ethernet/8390/ax88796.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index a72dfbc..eb72282 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -829,6 +829,7 @@ static int ax_remove(struct platform_device *pdev) release_mem_region(mem->start, resource_size(mem)); } + platform_set_drvdata(pdev, NULL); free_netdev(dev); return 0; @@ -962,6 +963,7 @@ static int ax_probe(struct platform_device *pdev) release_mem_region(mem->start, mem_size); exit_mem: + platform_set_drvdata(pdev, NULL); free_netdev(dev); return ret; -- 1.7.0.4
Add platform device driver to populate the ax88796 platform data from information provided by the XSurf100 zorro device driver. This driver will have to be loaded before loading the ax88796 module, or compiled as built-in. Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> --- drivers/net/ethernet/8390/Kconfig | 14 +- drivers/net/ethernet/8390/Makefile | 1 + drivers/net/ethernet/8390/xsurf100.c | 411 ++++++++++++++++++++++++++++++++++ 3 files changed, 425 insertions(+), 1 deletions(-) create mode 100644 drivers/net/ethernet/8390/xsurf100.c diff --git a/drivers/net/ethernet/8390/Kconfig b/drivers/net/ethernet/8390/Kconfig index fdc6734..0cadd45 100644 --- a/drivers/net/ethernet/8390/Kconfig +++ b/drivers/net/ethernet/8390/Kconfig @@ -30,7 +30,7 @@ config PCMCIA_AXNET config AX88796 tristate "ASIX AX88796 NE2000 clone support" - depends on (ARM || MIPS || SUPERH) + depends on (ARM || MIPS || SUPERH || AMIGA) select CRC32 select PHYLIB select MDIO_BITBANG @@ -45,6 +45,18 @@ config AX88796_93CX6 ---help--- Select this if your platform comes with an external 93CX6 eeprom. +config XSURF100 + tristate "Amiga XSurf 100 AX88796/NE2000 clone support" + depends on ZORRO + depends on AX88796 + ---help--- + This driver is for the Individual Computers X-Surf 100 Ethernet + card (based on the Asix AX88796 chip). If you have such a card, + say Y. Otherwise, say N. + + To compile this driver as a module, choose M here: the module + will be called xsurf100. + config HYDRA tristate "Hydra support" depends on ZORRO diff --git a/drivers/net/ethernet/8390/Makefile b/drivers/net/ethernet/8390/Makefile index f975c2f..3715f8d 100644 --- a/drivers/net/ethernet/8390/Makefile +++ b/drivers/net/ethernet/8390/Makefile @@ -16,4 +16,5 @@ obj-$(CONFIG_PCMCIA_PCNET) += pcnet_cs.o 8390.o obj-$(CONFIG_STNIC) += stnic.o 8390.o obj-$(CONFIG_ULTRA) += smc-ultra.o 8390.o obj-$(CONFIG_WD80x3) += wd.o 8390.o +obj-$(CONFIG_XSURF100) += xsurf100.o obj-$(CONFIG_ZORRO8390) += zorro8390.o 8390.o diff --git a/drivers/net/ethernet/8390/xsurf100.c b/drivers/net/ethernet/8390/xsurf100.c new file mode 100644 index 0000000..3caece0 --- /dev/null +++ b/drivers/net/ethernet/8390/xsurf100.c @@ -0,0 +1,411 @@ +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/platform_device.h> +#include <linux/zorro.h> +#include <net/ax88796.h> +#include <asm/amigaints.h> + +#define ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF100 \ + ZORRO_ID(INDIVIDUAL_COMPUTERS, 0x64, 0) + +#define XS100_IRQSTATUS_BASE 0x40 +#define XS100_8390_BASE 0x800 + +/* Longword-access area. Translated to 2 16-bit access cycles by the + * X-Surf 100 FPGA + */ +#define XS100_8390_DATA32_BASE 0x8000 +#define XS100_8390_DATA32_SIZE 0x2000 +/* Sub-Areas for fast data register access; addresses relative to area begin */ +#define XS100_8390_DATA_READ32_BASE 0x0880 +#define XS100_8390_DATA_WRITE32_BASE 0x0C80 +#define XS100_8390_DATA_AREA_SIZE 0x80 + +#define __NS8390_init ax_NS8390_init + +/* force unsigned long back to 'void __iomem *' */ +#define ax_convert_addr(_a) ((void __force __iomem *)(_a)) + +#define ei_inb(_a) z_readb(ax_convert_addr(_a)) +#define ei_outb(_v, _a) z_writeb(_v, ax_convert_addr(_a)) + +#define ei_inw(_a) z_readw(ax_convert_addr(_a)) +#define ei_outw(_v, _a) z_writew(_v, ax_convert_addr(_a)) + +#define ei_inb_p(_a) ei_inb(_a) +#define ei_outb_p(_v, _a) ei_outb(_v, _a) + +/* define EI_SHIFT() to take into account our register offsets */ +#define EI_SHIFT(x) (ei_local->reg_offset[(x)]) + +/* Ensure we have our RCR base value */ +#define AX88796_PLATFORM + +static unsigned char version[] = + "ax88796.c: Copyright 2005,2007 Simtec Electronics\n"; + +#include "lib8390.c" + +/* from ne.c */ +#define NE_CMD EI_SHIFT(0x00) +#define NE_RESET EI_SHIFT(0x1f) +#define NE_DATAPORT EI_SHIFT(0x10) + +/* Hard reset the card. This used to pause for the same period that a + * 8390 reset command required, but that shouldn't be necessary. + */ +static void ax_reset_8390(struct net_device *dev) +{ + struct ei_device *ei_local = netdev_priv(dev); + unsigned long reset_start_time = jiffies; + void __iomem *addr = (void __iomem *)dev->base_addr; + + netif_dbg(ei_local, hw, dev, "resetting the 8390 t=%ld...\n", jiffies); + + ei_outb(ei_inb(addr + NE_RESET), addr + NE_RESET); + + ei_local->txing = 0; + ei_local->dmaing = 0; + + /* This check _should_not_ be necessary, omit eventually. */ + while ((ei_inb(addr + EN0_ISR) & ENISR_RESET) == 0) { + if (time_after(jiffies, reset_start_time + 2 * HZ / 100)) { + netdev_warn(dev, "%s: did not complete.\n", __func__); + break; + } + } + + ei_outb(ENISR_RESET, addr + EN0_ISR); /* Ack intr. */ +} + +struct xsurf100_ax_plat_data { + struct ax_plat_data ax; + void __iomem *base_regs; + void __iomem *data_area; +}; + +static int is_xsurf100_network_irq(struct platform_device *pdev) +{ + struct xsurf100_ax_plat_data *xs100 = dev_get_platdata(&pdev->dev); + + return (readw(xs100->base_regs + XS100_IRQSTATUS_BASE) & 0xaaaa) != 0; +} + +/* These functions guarantee that the iomem is accessed with 32 bit + * cycles only. z_memcpy_fromio / z_memcpy_toio don't + */ +static void z_memcpy_fromio32(void *dst, const void __iomem *src, size_t bytes) +{ + while (bytes > 32) { + asm __volatile__ + ("movem.l (%0)+,%%d0-%%d7\n" + "movem.l %%d0-%%d7,(%1)\n" + "adda.l #32,%1" : "=a"(src), "=a"(dst) + : "0"(src), "1"(dst) : "d0", "d1", "d2", "d3", "d4", + "d5", "d6", "d7", "memory"); + bytes -= 32; + } + while (bytes) { + *(uint32_t *)dst = z_readl(src); + src += 4; + dst += 4; + bytes -= 4; + } +} + +static void z_memcpy_toio32(void __iomem *dst, const void *src, size_t bytes) +{ + while (bytes) { + z_writel(*(const uint32_t *)src, dst); + src += 4; + dst += 4; + bytes -= 4; + } +} + +static void xs100_write(struct net_device *dev, const void *src, + unsigned int count) +{ + struct ei_device *ei_local = netdev_priv(dev); + struct platform_device *pdev = to_platform_device(dev->dev.parent); + struct xsurf100_ax_plat_data *xs100 = dev_get_platdata(&pdev->dev); + + /* copy whole blocks */ + while (count > XS100_8390_DATA_AREA_SIZE) { + z_memcpy_toio32(xs100->data_area + + XS100_8390_DATA_WRITE32_BASE, src, + XS100_8390_DATA_AREA_SIZE); + src += XS100_8390_DATA_AREA_SIZE; + count -= XS100_8390_DATA_AREA_SIZE; + } + /* copy whole dwords */ + z_memcpy_toio32(xs100->data_area + XS100_8390_DATA_WRITE32_BASE, + src, count & ~3); + src += count & ~3; + if (count & 2) { + ei_outw(*(uint16_t *)src, ei_local->mem + NE_DATAPORT); + src += 2; + } + if (count & 1) + ei_outb(*(uint8_t *)src, ei_local->mem + NE_DATAPORT); +} + +static void xs100_read(struct net_device *dev, void *dst, unsigned int count) +{ + struct ei_device *ei_local = netdev_priv(dev); + struct platform_device *pdev = to_platform_device(dev->dev.parent); + struct xsurf100_ax_plat_data *xs100 = dev_get_platdata(&pdev->dev); + + /* copy whole blocks */ + while (count > XS100_8390_DATA_AREA_SIZE) { + z_memcpy_fromio32(dst, xs100->data_area + + XS100_8390_DATA_READ32_BASE, + XS100_8390_DATA_AREA_SIZE); + dst += XS100_8390_DATA_AREA_SIZE; + count -= XS100_8390_DATA_AREA_SIZE; + } + /* copy whole dwords */ + z_memcpy_fromio32(dst, xs100->data_area + XS100_8390_DATA_READ32_BASE, + count & ~3); + dst += count & ~3; + if (count & 2) { + *(uint16_t *)dst = ei_inw(ei_local->mem + NE_DATAPORT); + dst += 2; + } + if (count & 1) + *(uint8_t *)dst = ei_inb(ei_local->mem + NE_DATAPORT); +} + +/* Block input and output, similar to the Crynwr packet driver. If + * you are porting to a new ethercard, look at the packet driver + * source for hints. The NEx000 doesn't share the on-board packet + * memory -- you have to put the packet out through the "remote DMA" + * dataport using ei_outb. + */ +static void xs100_block_input(struct net_device *dev, int count, + struct sk_buff *skb, int ring_offset) +{ + struct ei_device *ei_local = netdev_priv(dev); + void __iomem *nic_base = ei_local->mem; + char *buf = skb->data; + + if (ei_local->dmaing) { + netdev_err(dev, + "DMAing conflict in %s " + "[DMAstat:%d][irqlock:%d].\n", + __func__, + ei_local->dmaing, ei_local->irqlock); + return; + } + + ei_local->dmaing |= 0x01; + + ei_outb(E8390_NODMA + E8390_PAGE0 + E8390_START, nic_base + NE_CMD); + ei_outb(count & 0xff, nic_base + EN0_RCNTLO); + ei_outb(count >> 8, nic_base + EN0_RCNTHI); + ei_outb(ring_offset & 0xff, nic_base + EN0_RSARLO); + ei_outb(ring_offset >> 8, nic_base + EN0_RSARHI); + ei_outb(E8390_RREAD + E8390_START, nic_base + NE_CMD); + + xs100_read(dev, buf, count); + + ei_local->dmaing &= ~1; +} + +static void xs100_block_output(struct net_device *dev, int count, + const unsigned char *buf, const int start_page) +{ + struct ei_device *ei_local = netdev_priv(dev); + void __iomem *nic_base = ei_local->mem; + unsigned long dma_start; + + /* Round the count up for word writes. Do we need to do this? + * What effect will an odd byte count have on the 8390? I + * should check someday. + */ + if (ei_local->word16 && (count & 0x01)) + count++; + + /* This *shouldn't* happen. If it does, it's the last thing + * you'll see + */ + if (ei_local->dmaing) { + netdev_err(dev, "DMAing conflict in %s " + "[DMAstat:%d][irqlock:%d]\n", + __func__, + ei_local->dmaing, ei_local->irqlock); + return; + } + + ei_local->dmaing |= 0x01; + /* We should already be in page 0, but to be safe... */ + ei_outb(E8390_PAGE0 + E8390_START + E8390_NODMA, nic_base + NE_CMD); + + ei_outb(ENISR_RDC, nic_base + EN0_ISR); + + /* Now the normal output. */ + ei_outb(count & 0xff, nic_base + EN0_RCNTLO); + ei_outb(count >> 8, nic_base + EN0_RCNTHI); + ei_outb(0x00, nic_base + EN0_RSARLO); + ei_outb(start_page, nic_base + EN0_RSARHI); + + ei_outb(E8390_RWRITE + E8390_START, nic_base + NE_CMD); + + xs100_write(dev, buf, count); + + dma_start = jiffies; + + while ((ei_inb(nic_base + EN0_ISR) & ENISR_RDC) == 0) { + if (jiffies - dma_start > 2 * HZ / 100) { /* 20ms */ + netdev_warn(dev, "timeout waiting for Tx RDC.\n"); + ax_reset_8390(dev); + ax_NS8390_init(dev, 1); + break; + } + } + + ei_outb(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ + ei_local->dmaing &= ~0x01; +} + +static int xsurf100_probe(struct zorro_dev *zdev, + const struct zorro_device_id *ent) +{ + struct platform_device *pdev; + struct xsurf100_ax_plat_data ax88796_data; + struct resource res[2] = { + DEFINE_RES_NAMED(IRQ_AMIGA_PORTS, 1, NULL, + IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE), + DEFINE_RES_MEM(zdev->resource.start + XS100_8390_BASE, + 4 * 0x20) + }; + int reg; + /* This table is referenced in the device structure, so it must + * outlive the scope of xsurf100_probe. + */ + static u32 reg_offsets[32]; + int ret = 0; + + /* X-Surf 100 control and 32 bit ring buffer data access areas. + * These resources are not used by the ax88796 driver, so must + * be requested here and passed via platform data. + */ + + if (!request_mem_region(zdev->resource.start, 0x100, zdev->name)) { + dev_err(&zdev->dev, "cannot reserve X-Surf 100 control registers\n"); + return -ENXIO; + } + + if (!request_mem_region(zdev->resource.start + + XS100_8390_DATA32_BASE, + XS100_8390_DATA32_SIZE, + "X-Surf 100 32-bit data access")) { + dev_err(&zdev->dev, "cannot reserve 32-bit area\n"); + ret = -ENXIO; + goto exit_req; + } + + for (reg = 0; reg < 0x20; reg++) + reg_offsets[reg] = 4 * reg; + + memset(&ax88796_data, 0, sizeof(ax88796_data)); + ax88796_data.ax.flags = AXFLG_HAS_EEPROM; + ax88796_data.ax.wordlength = 2; + ax88796_data.ax.dcr_val = 0x48; + ax88796_data.ax.rcr_val = 0x40; + ax88796_data.ax.reg_offsets = reg_offsets; + ax88796_data.ax.check_irq = is_xsurf100_network_irq; + ax88796_data.base_regs = ioremap(zdev->resource.start, 0x100); + + /* error handling for ioremap regs */ + if (!ax88796_data.base_regs) { + dev_err(&zdev->dev, "Cannot ioremap area %p (registers)\n", + (void *)zdev->resource.start); + + ret = -ENXIO; + goto exit_req2; + } + + ax88796_data.data_area = ioremap(zdev->resource.start + + XS100_8390_DATA32_BASE, XS100_8390_DATA32_SIZE); + + /* error handling for ioremap data */ + if (!ax88796_data.data_area) { + dev_err(&zdev->dev, "Cannot ioremap area %p (32-bit access)\n", + (void *)zdev->resource.start + XS100_8390_DATA32_BASE); + + ret = -ENXIO; + goto exit_mem; + } + + ax88796_data.ax.block_output = xs100_block_output; + ax88796_data.ax.block_input = xs100_block_input; + + pdev = platform_device_register_resndata(&zdev->dev, "ax88796", + zdev->slotaddr, res, 2, + &ax88796_data, + sizeof(ax88796_data)); + + if (IS_ERR(pdev)) { + dev_err(&zdev->dev, "cannot register platform device\n"); + ret = -ENXIO; + goto exit_mem2; + } + + zorro_set_drvdata(zdev, pdev); + + if (!ret) + return 0; + + exit_mem2: + iounmap(ax88796_data.data_area); + + exit_mem: + iounmap(ax88796_data.base_regs); + + exit_req2: + release_mem_region(zdev->resource.start + XS100_8390_DATA32_BASE, + XS100_8390_DATA32_SIZE); + + exit_req: + release_mem_region(zdev->resource.start, 0x100); + + return ret; +} + +static void xsurf100_remove(struct zorro_dev *zdev) +{ + struct platform_device *pdev; + struct xsurf100_ax_plat_data *xs100; + + pdev = zorro_get_drvdata(zdev); + xs100 = dev_get_platdata(&pdev->dev); + + platform_device_unregister(pdev); + + iounmap(xs100->base_regs); + release_mem_region(zdev->resource.start, 0x100); + iounmap(xs100->data_area); + release_mem_region(zdev->resource.start + XS100_8390_DATA32_BASE, + XS100_8390_DATA32_SIZE); +} + +static const struct zorro_device_id xsurf100_zorro_tbl[] = { + { ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF100, }, + { 0 } +}; + +MODULE_DEVICE_TABLE(zorro, xsurf100_zorro_tbl); + +static struct zorro_driver xsurf100_driver = { + .name = "xsurf100", + .id_table = xsurf100_zorro_tbl, + .probe = xsurf100_probe, + .remove = xsurf100_remove, +}; + +module_driver(xsurf100_driver, zorro_register_driver, zorro_unregister_driver); + +MODULE_DESCRIPTION("X-Surf 100 driver"); +MODULE_AUTHOR("Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de>"); +MODULE_LICENSE("GPL v2"); -- 1.7.0.4
[Andrew, sorry for the dup. I did hit reply-to-auhor instead of reply-to-all first.] Andrew Lunn schrieb: >> > This should really be fixed in the PHY driver, not the MAC. >> >> OK - do you want this separate, or as part of this series? Might have >> a few side effects on more commonly used hardware, perhaps? > > Hi Michael > > What PHY driver is used? The ax88796b comes with its own integrated (buggy) PHY needing this workaround. This PHY has its own ID which is not known by Linux, so it is using the genphy driver as fallback. > In the driver you can implement a .soft_reset > function which first does the dummy write, and then uses > genphy_soft_reset() to do the actual reset. We could do that - but I dont't see the point in creating a PHY driver that is only ever used by this MAC driver, just to add a single line to the genphy driver. If the same PHY might be used with a different MAC, you definitely would have a point there, though. Kind regards, Michael Karcher
Hi Michael, Adrian, Thanks for your patch! On Tue, Apr 17, 2018 at 4:08 AM, Michael Schmitz <schmitzmic@gmail.com> wrote: > From: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> > > This complements the fix in 82533ad9a1c that removed the free_irq Please quote the commit's subject, too, like ... fix in commit 82533ad9a1 ("net: ethernet: ax88796: don't call free_irq without request_irq first") BTW, I have a git alias for that: $ git help fixes `git fixes' is aliased to `show --format='Fixes: %h ("%s")' -s' $ git fixes 82533ad9a1c Fixes: 82533ad9a1c ("net: ethernet: ax88796: don't call free_irq without request_irq first") > call in the error path of probe, to also not call free_irq when > remove is called to revert the effects of probe. > > Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> The patch is authored by Adrian, but his SoB is missing? Michael (Schmitz): as you took the patch, you should add your SoB, too. For the actual patch contents: Reviewed-by: Geert Uytterhoeven <geert@linux-m68k.org> Gr{oetje,eeting}s, Geert -- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds
Hello! On 4/17/2018 1:04 AM, Michael Schmitz wrote: > From: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> > > This complements the fix in 82533ad9a1c that removed the free_irq You also need to specify the commit's summary line enclosed in (""). > call in the error path of probe, to also not call free_irq when > remove is called to revert the effects of probe. > > Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> [...] MBR, Sergei
On 04/17/2018 04:08 AM, Michael Schmitz wrote:
> From: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
This should be:
From: Michael Karcher <debian@mkarcher.dialup.fu-berlin.de>
--
.''`. John Paul Adrian Glaubitz
: :' : Debian Developer - glaubitz@debian.org
`. `' Freie Universitaet Berlin - glaubitz@physik.fu-berlin.de
`- GPG: 62FF 8A75 84E0 2956 9546 0006 7426 3B37 F5B5 F913
On 04/17/2018 04:08 AM, Michael Schmitz wrote:
> From: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
This should be:
From: Michael Karcher <debian@mkarcher.dialup.fu-berlin.de>
--
.''`. John Paul Adrian Glaubitz
: :' : Debian Developer - glaubitz@debian.org
`. `' Freie Universitaet Berlin - glaubitz@physik.fu-berlin.de
`- GPG: 62FF 8A75 84E0 2956 9546 0006 7426 3B37 F5B5 F913
On Tue, Apr 17, 2018 at 07:18:10AM +0200, Michael Karcher wrote:
> [Andrew, sorry for the dup. I did hit reply-to-auhor instead of
> reply-to-all first.]
>
> Andrew Lunn schrieb:
> >> > This should really be fixed in the PHY driver, not the MAC.
> >>
> >> OK - do you want this separate, or as part of this series? Might have
> >> a few side effects on more commonly used hardware, perhaps?
> >
> > Hi Michael
> >
> > What PHY driver is used?
> The ax88796b comes with its own integrated (buggy) PHY needing this
> workaround. This PHY has its own ID which is not known by Linux, so it is
> using the genphy driver as fallback.
>
> > In the driver you can implement a .soft_reset
> > function which first does the dummy write, and then uses
> > genphy_soft_reset() to do the actual reset.
> We could do that - but I dont't see the point in creating a PHY driver
> that is only ever used by this MAC driver, just to add a single line to
> the genphy driver. If the same PHY might be used with a different MAC,
> you definitely would have a point there, though.
Hi Michael
We try to keep the core code clean, and put all workarounds for buggy
hardware in drivers specific to them. It just helps keep the core code
maintainable.
I would prefer a driver specific to this PHY with the workaround. But
lets see what Florian says.
Andrew
On Tue, Apr 17, 2018 at 02:08:09PM +1200, Michael Schmitz wrote:
> From: Michael Karcher <debian@mkarcher.dialup.fu-berlin.de>
>
> Call ax_mii_init in ax_open(), and unregister/remove mdiobus resources
> in ax_close().
>
> This is needed to be able to unload the module, as the module is busy
> while the MII bus is attached.
>
> Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de>
> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
On Tue, Apr 17, 2018 at 02:08:15PM +1200, Michael Schmitz wrote:
> Add platform device driver to populate the ax88796 platform data from
> information provided by the XSurf100 zorro device driver.
> This driver will have to be loaded before loading the ax88796 module,
> or compiled as built-in.
>
> Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de>
> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com>
> ---
> drivers/net/ethernet/8390/Kconfig | 14 +-
> drivers/net/ethernet/8390/Makefile | 1 +
> drivers/net/ethernet/8390/xsurf100.c | 411 ++++++++++++++++++++++++++++++++++
> 3 files changed, 425 insertions(+), 1 deletions(-)
> create mode 100644 drivers/net/ethernet/8390/xsurf100.c
>
> diff --git a/drivers/net/ethernet/8390/Kconfig b/drivers/net/ethernet/8390/Kconfig
> index fdc6734..0cadd45 100644
> --- a/drivers/net/ethernet/8390/Kconfig
> +++ b/drivers/net/ethernet/8390/Kconfig
> @@ -30,7 +30,7 @@ config PCMCIA_AXNET
>
> config AX88796
> tristate "ASIX AX88796 NE2000 clone support"
> - depends on (ARM || MIPS || SUPERH)
> + depends on (ARM || MIPS || SUPERH || AMIGA)
Hi Michael
Will it compile on other platforms? If so, it is a good idea to add
COMPILE_TEST as well.
Andrew
From: Geert Uytterhoeven <geert@linux-m68k.org>
Date: Tue, 17 Apr 2018 10:20:25 +0200
> BTW, I have a git alias for that:
>
> $ git help fixes
> `git fixes' is aliased to `show --format='Fixes: %h ("%s")' -s'
> $ git fixes 82533ad9a1c
> Fixes: 82533ad9a1c ("net: ethernet: ax88796: don't call free_irq
> without request_irq first")
Thanks for sharing :)
Hi Michael, Thanks for your patch! On Tue, Apr 17, 2018 at 12:04 AM, Michael Schmitz <schmitzmic@gmail.com> wrote: > Add platform device driver to populate the ax88796 platform data from > information provided by the XSurf100 zorro device driver. > This driver will have to be loaded before loading the ax88796 module, > or compiled as built-in. Is that really true? The platform device should be probed when both the device and driver have been registered, but order shouldn't matter. > Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Missing "From: Michael Karcher ..."? > Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> > --- a/drivers/net/ethernet/8390/Kconfig > +++ b/drivers/net/ethernet/8390/Kconfig > @@ -30,7 +30,7 @@ config PCMCIA_AXNET > > config AX88796 > tristate "ASIX AX88796 NE2000 clone support" > - depends on (ARM || MIPS || SUPERH) > + depends on (ARM || MIPS || SUPERH || AMIGA) s/AMIGA/ZORRO/, for consistency with the below. > select CRC32 > select PHYLIB > select MDIO_BITBANG > @@ -45,6 +45,18 @@ config AX88796_93CX6 > ---help--- > Select this if your platform comes with an external 93CX6 eeprom. > > +config XSURF100 > + tristate "Amiga XSurf 100 AX88796/NE2000 clone support" > + depends on ZORRO > + depends on AX88796 It's a bit unfortunate the user has to enable _two_ config options to enable this driver. I see two solutions for that: 1) Hide the XSURF100 symbol, so it gets enabled automatically if AX88796 is enabled on a Zorro bus system: config XSURF100 tristate depends on ZORRO default AX88796 2) Hide the AX88796 symbol, and let it be selected by XSURF100: config AX88796 tristate "ASIX AX88796 NE2000 clone support" if !ZORRO depends on ARM || MIPS || SUPERH || ZORRO ... config XSURF100 tristate "Amiga XSurf 100 AX88796/NE2000 clone support" depends on ZORRO select AX88796 > --- /dev/null > +++ b/drivers/net/ethernet/8390/xsurf100.c > @@ -0,0 +1,411 @@ > +#include <linux/module.h> > +#include <linux/netdevice.h> > +#include <linux/platform_device.h> > +#include <linux/zorro.h> > +#include <net/ax88796.h> > +#include <asm/amigaints.h> > + > +#define ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF100 \ > + ZORRO_ID(INDIVIDUAL_COMPUTERS, 0x64, 0) Another long define to get rid of? ;-) > +/* Hard reset the card. This used to pause for the same period that a > + * 8390 reset command required, but that shouldn't be necessary. > + */ > +static void ax_reset_8390(struct net_device *dev) > +{ > + struct ei_device *ei_local = netdev_priv(dev); > + unsigned long reset_start_time = jiffies; > + void __iomem *addr = (void __iomem *)dev->base_addr; > + > + netif_dbg(ei_local, hw, dev, "resetting the 8390 t=%ld...\n", jiffies); > + > + ei_outb(ei_inb(addr + NE_RESET), addr + NE_RESET); > + > + ei_local->txing = 0; > + ei_local->dmaing = 0; > + > + /* This check _should_not_ be necessary, omit eventually. */ > + while ((ei_inb(addr + EN0_ISR) & ENISR_RESET) == 0) { > + if (time_after(jiffies, reset_start_time + 2 * HZ / 100)) { > + netdev_warn(dev, "%s: did not complete.\n", __func__); > + break; > + } cpu_relax()? How long does this usually take? If > 1 ms, you can use e.g. msleep(1) instead of cpu_relax(). > + } > + > + ei_outb(ENISR_RESET, addr + EN0_ISR); /* Ack intr. */ > +} > + if (ei_local->dmaing) { > + netdev_err(dev, > + "DMAing conflict in %s " > + "[DMAstat:%d][irqlock:%d].\n", Please don't split error messages, as that makes it more difficult to grep for them. > + __func__, > + ei_local->dmaing, ei_local->irqlock); > + return; > +static int xsurf100_probe(struct zorro_dev *zdev, > + const struct zorro_device_id *ent) > +{ > + /* error handling for ioremap regs */ > + if (!ax88796_data.base_regs) { > + dev_err(&zdev->dev, "Cannot ioremap area %p (registers)\n", > + (void *)zdev->resource.start); Please use %pR to format struct resource. Documentation/core-api/printk-formats.rst > + /* error handling for ioremap data */ > + if (!ax88796_data.data_area) { > + dev_err(&zdev->dev, "Cannot ioremap area %p (32-bit access)\n", > + (void *)zdev->resource.start + XS100_8390_DATA32_BASE); %pR > +static void xsurf100_remove(struct zorro_dev *zdev) > +{ > + struct platform_device *pdev; > + struct xsurf100_ax_plat_data *xs100; > + > + pdev = zorro_get_drvdata(zdev); > + xs100 = dev_get_platdata(&pdev->dev); struct platform_device *pdev = pdev = zorro_get_drvdata(zdev); struct xsurf100_ax_plat_data *xs100 = dev_get_platdata(&pdev->dev); Gr{oetje,eeting}s, Geert -- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds
On 04/17/2018 06:01 AM, Andrew Lunn wrote:
> On Tue, Apr 17, 2018 at 07:18:10AM +0200, Michael Karcher wrote:
>> [Andrew, sorry for the dup. I did hit reply-to-auhor instead of
>> reply-to-all first.]
>>
>> Andrew Lunn schrieb:
>>>>> This should really be fixed in the PHY driver, not the MAC.
>>>>
>>>> OK - do you want this separate, or as part of this series? Might have
>>>> a few side effects on more commonly used hardware, perhaps?
>>>
>>> Hi Michael
>>>
>>> What PHY driver is used?
>> The ax88796b comes with its own integrated (buggy) PHY needing this
>> workaround. This PHY has its own ID which is not known by Linux, so it is
>> using the genphy driver as fallback.
>>
>>> In the driver you can implement a .soft_reset
>>> function which first does the dummy write, and then uses
>>> genphy_soft_reset() to do the actual reset.
>> We could do that - but I dont't see the point in creating a PHY driver
>> that is only ever used by this MAC driver, just to add a single line to
>> the genphy driver. If the same PHY might be used with a different MAC,
>> you definitely would have a point there, though.
>
>
> Hi Michael
>
> We try to keep the core code clean, and put all workarounds for buggy
> hardware in drivers specific to them. It just helps keep the core code
> maintainable.
>
> I would prefer a driver specific to this PHY with the workaround. But
> lets see what Florian says.
If you are already using the generic PHY driver, coming up with a custom
one that only overrides the soft_reset and/or config_init callback is
really not that much work, and as Andrew says, it helps make things
clearer and properly isolated. As far as where to place that driver, you
can either create a new file under drivers/net/phy/* or you can even
register a phy_driver instance from within ax88796 if that makes it any
clearer.
FWIW, there are plenty of examples where there is a PHY driver used by a
single MAC, and that is perfectly fine, because the abstraction is still
preserved.
--
Florian
[-- Attachment #1: Type: text/plain, Size: 2005 bytes --] Hi Michael, I love your patch! Perhaps something to improve: [auto build test WARNING on v4.16] [cannot apply to net-next/master net/master v4.17-rc1 next-20180417] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system] url: https://github.com/0day-ci/linux/commits/Michael-Schmitz/New-network-driver-for-Amiga-X-Surf-100-m68k/20180417-141150 config: arm-samsung (attached as .config) compiler: arm-linux-gnueabi-gcc (Debian 7.2.0-11) 7.2.0 reproduce: wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # save the attached .config to linux build tree make.cross ARCH=arm All warnings (new ones prefixed by >>): In file included from arch/arm/mach-s3c24xx/mach-anubis.c:42:0: >> include/net/ax88796.h:35:11: warning: 'struct sk_buff' declared inside parameter list will not be visible outside of this definition or declaration struct sk_buff *skb, int ring_offset); ^~~~~~~ vim +35 include/net/ax88796.h 20 21 struct ax_plat_data { 22 unsigned int flags; 23 unsigned char wordlength; /* 1 or 2 */ 24 unsigned char dcr_val; /* default value for DCR */ 25 unsigned char rcr_val; /* default value for RCR */ 26 unsigned char gpoc_val; /* default value for GPOC */ 27 u32 *reg_offsets; /* register offsets */ 28 u8 *mac_addr; /* MAC addr (only used when 29 AXFLG_MAC_FROMPLATFORM is used */ 30 31 /* uses default ax88796 buffer if set to NULL */ 32 void (*block_output)(struct net_device *dev, int count, 33 const unsigned char *buf, int star_page); 34 void (*block_input)(struct net_device *dev, int count, > 35 struct sk_buff *skb, int ring_offset); 36 }; 37 --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation [-- Attachment #2: .config.gz --] [-- Type: application/gzip, Size: 22607 bytes --]
Thanks Florian,
I'll keep the Asix PHY driver separate from ax88796 for now. Mainly to
simplify testing. Let's see whether it can be used by any other MAC -
can still fold it into ax88796 later.
Cheers,
Michael
On Wed, Apr 18, 2018 at 6:08 AM, Florian Fainelli <f.fainelli@gmail.com> wrote:
> On 04/17/2018 06:01 AM, Andrew Lunn wrote:
>> On Tue, Apr 17, 2018 at 07:18:10AM +0200, Michael Karcher wrote:
>>> [Andrew, sorry for the dup. I did hit reply-to-auhor instead of
>>> reply-to-all first.]
>>>
>>> Andrew Lunn schrieb:
>>>>>> This should really be fixed in the PHY driver, not the MAC.
>>>>>
>>>>> OK - do you want this separate, or as part of this series? Might have
>>>>> a few side effects on more commonly used hardware, perhaps?
>>>>
>>>> Hi Michael
>>>>
>>>> What PHY driver is used?
>>> The ax88796b comes with its own integrated (buggy) PHY needing this
>>> workaround. This PHY has its own ID which is not known by Linux, so it is
>>> using the genphy driver as fallback.
>>>
>>>> In the driver you can implement a .soft_reset
>>>> function which first does the dummy write, and then uses
>>>> genphy_soft_reset() to do the actual reset.
>>> We could do that - but I dont't see the point in creating a PHY driver
>>> that is only ever used by this MAC driver, just to add a single line to
>>> the genphy driver. If the same PHY might be used with a different MAC,
>>> you definitely would have a point there, though.
>>
>>
>> Hi Michael
>>
>> We try to keep the core code clean, and put all workarounds for buggy
>> hardware in drivers specific to them. It just helps keep the core code
>> maintainable.
>>
>> I would prefer a driver specific to this PHY with the workaround. But
>> lets see what Florian says.
>
> If you are already using the generic PHY driver, coming up with a custom
> one that only overrides the soft_reset and/or config_init callback is
> really not that much work, and as Andrew says, it helps make things
> clearer and properly isolated. As far as where to place that driver, you
> can either create a new file under drivers/net/phy/* or you can even
> register a phy_driver instance from within ax88796 if that makes it any
> clearer.
>
> FWIW, there are plenty of examples where there is a PHY driver used by a
> single MAC, and that is perfectly fine, because the abstraction is still
> preserved.
> --
> Florian
Hi Adrian,
On Tue, Apr 17, 2018 at 11:40 PM, John Paul Adrian Glaubitz
<glaubitz@physik.fu-berlin.de> wrote:
> On 04/17/2018 04:08 AM, Michael Schmitz wrote:
>>
>> From: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
>
> This should be:
>
> From: Michael Karcher <debian@mkarcher.dialup.fu-berlin.de>
I haven't found a way to change that in my tree yet, sorry. Unless
someone has a simple way to fix patch authorship after a merge, I may
have to reimport from scratch.
Cheers,
Michael
Thanks Geert, I'll fix that.
I see my v2 series shows up as new series on patchwork - do I need to
do something different when tagging the next version, Dave?
Cheers,
Michael
On Wed, Apr 18, 2018 at 1:51 AM, David Miller <davem@davemloft.net> wrote:
> From: Geert Uytterhoeven <geert@linux-m68k.org>
> Date: Tue, 17 Apr 2018 10:20:25 +0200
>
>> BTW, I have a git alias for that:
>>
>> $ git help fixes
>> `git fixes' is aliased to `show --format='Fixes: %h ("%s")' -s'
>> $ git fixes 82533ad9a1c
>> Fixes: 82533ad9a1c ("net: ethernet: ax88796: don't call free_irq
>> without request_irq first")
>
> Thanks for sharing :)
On 04/17/2018 10:32 PM, Michael Schmitz wrote:
>> From: Michael Karcher <debian@mkarcher.dialup.fu-berlin.de>
>
> I haven't found a way to change that in my tree yet, sorry. Unless
> someone has a simple way to fix patch authorship after a merge, I may
> have to reimport from scratch.
I guess you'll have to re-import then, sorry :(.
The correct mail address is:
Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de>
which Michael uses for all his kernel work.
Adrian
--
.''`. John Paul Adrian Glaubitz
: :' : Debian Developer - glaubitz@debian.org
`. `' Freie Universitaet Berlin - glaubitz@physik.fu-berlin.de
`- GPG: 62FF 8A75 84E0 2956 9546 0006 7426 3B37 F5B5 F913
On Wed, Apr 18, 2018 at 08:32:25AM +1200, Michael Schmitz wrote:
> Hi Adrian,
>
> On Tue, Apr 17, 2018 at 11:40 PM, John Paul Adrian Glaubitz
> <glaubitz@physik.fu-berlin.de> wrote:
> > On 04/17/2018 04:08 AM, Michael Schmitz wrote:
> >>
> >> From: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
> >
> > This should be:
> >
> > From: Michael Karcher <debian@mkarcher.dialup.fu-berlin.de>
>
> I haven't found a way to change that in my tree yet, sorry. Unless
> someone has a simple way to fix patch authorship after a merge, I may
> have to reimport from scratch.
git commit --am --author=<author>
Andrew
Hi Andrew,
thanks, that's what I was looking for. The next version will have all
but one patch correctly attributed to Michael Karcher.
Cheers,
Michael
On Wed, Apr 18, 2018 at 9:13 AM, Andrew Lunn <andrew@lunn.ch> wrote:
> On Wed, Apr 18, 2018 at 08:32:25AM +1200, Michael Schmitz wrote:
>> Hi Adrian,
>>
>> On Tue, Apr 17, 2018 at 11:40 PM, John Paul Adrian Glaubitz
>> <glaubitz@physik.fu-berlin.de> wrote:
>> > On 04/17/2018 04:08 AM, Michael Schmitz wrote:
>> >>
>> >> From: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
>> >
>> > This should be:
>> >
>> > From: Michael Karcher <debian@mkarcher.dialup.fu-berlin.de>
>>
>> I haven't found a way to change that in my tree yet, sorry. Unless
>> someone has a simple way to fix patch authorship after a merge, I may
>> have to reimport from scratch.
>
> git commit --am --author=<author>
>
> Andrew
Hi Geert, thanks for your suggestions! On Wed, Apr 18, 2018 at 1:53 AM, Geert Uytterhoeven <geert@linux-m68k.org> wrote: > Hi Michael, > > Thanks for your patch! > > On Tue, Apr 17, 2018 at 12:04 AM, Michael Schmitz <schmitzmic@gmail.com> wrote: >> Add platform device driver to populate the ax88796 platform data from >> information provided by the XSurf100 zorro device driver. >> This driver will have to be loaded before loading the ax88796 module, >> or compiled as built-in. > > Is that really true? The platform device should be probed when both the > device and driver have been registered, but order shouldn't matter. Loading the xsurf100 module will pull in the ax88796 module, so order does not matter. I'll drop that. > >> Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> > > Missing "From: Michael Karcher ..."? Fixed the authorship now - probably got mangled when squashing in my local edits. > >> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> > >> --- a/drivers/net/ethernet/8390/Kconfig >> +++ b/drivers/net/ethernet/8390/Kconfig >> @@ -30,7 +30,7 @@ config PCMCIA_AXNET >> >> config AX88796 >> tristate "ASIX AX88796 NE2000 clone support" >> - depends on (ARM || MIPS || SUPERH) >> + depends on (ARM || MIPS || SUPERH || AMIGA) > > s/AMIGA/ZORRO/, for consistency with the below. Will do. > >> select CRC32 >> select PHYLIB >> select MDIO_BITBANG >> @@ -45,6 +45,18 @@ config AX88796_93CX6 >> ---help--- >> Select this if your platform comes with an external 93CX6 eeprom. >> >> +config XSURF100 >> + tristate "Amiga XSurf 100 AX88796/NE2000 clone support" >> + depends on ZORRO >> + depends on AX88796 > > It's a bit unfortunate the user has to enable _two_ config options to enable > this driver. > > I see two solutions for that: > > 1) Hide the XSURF100 symbol, so it gets enabled automatically if AX88796 is > enabled on a Zorro bus system: > > config XSURF100 > tristate > depends on ZORRO > default AX88796 > > 2) Hide the AX88796 symbol, and let it be selected by XSURF100: > > config AX88796 > tristate "ASIX AX88796 NE2000 clone support" if !ZORRO > depends on ARM || MIPS || SUPERH || ZORRO > ... > > config XSURF100 > tristate "Amiga XSurf 100 AX88796/NE2000 clone support" > depends on ZORRO > select AX88796 I'll use the latter - >> --- /dev/null >> +++ b/drivers/net/ethernet/8390/xsurf100.c >> @@ -0,0 +1,411 @@ >> +#include <linux/module.h> >> +#include <linux/netdevice.h> >> +#include <linux/platform_device.h> >> +#include <linux/zorro.h> >> +#include <net/ax88796.h> >> +#include <asm/amigaints.h> >> + >> +#define ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF100 \ >> + ZORRO_ID(INDIVIDUAL_COMPUTERS, 0x64, 0) > > Another long define to get rid of? ;-) > >> +/* Hard reset the card. This used to pause for the same period that a >> + * 8390 reset command required, but that shouldn't be necessary. >> + */ >> +static void ax_reset_8390(struct net_device *dev) >> +{ >> + struct ei_device *ei_local = netdev_priv(dev); >> + unsigned long reset_start_time = jiffies; >> + void __iomem *addr = (void __iomem *)dev->base_addr; >> + >> + netif_dbg(ei_local, hw, dev, "resetting the 8390 t=%ld...\n", jiffies); >> + >> + ei_outb(ei_inb(addr + NE_RESET), addr + NE_RESET); >> + >> + ei_local->txing = 0; >> + ei_local->dmaing = 0; >> + >> + /* This check _should_not_ be necessary, omit eventually. */ >> + while ((ei_inb(addr + EN0_ISR) & ENISR_RESET) == 0) { >> + if (time_after(jiffies, reset_start_time + 2 * HZ / 100)) { >> + netdev_warn(dev, "%s: did not complete.\n", __func__); >> + break; >> + } > > cpu_relax()? > > How long does this usually take? If > 1 ms, you can use e.g. msleep(1) > instead of cpu_relax(). No idea how long this will take - the reset function is lifted straight out of ax88796.c with no modifications whatsoever. Come to think of it - it's exported as ei_local->reset_8390 there, so there is no good reason for even duplicating the code that I can see. I'lll drop it. > >> + } >> + >> + ei_outb(ENISR_RESET, addr + EN0_ISR); /* Ack intr. */ >> +} > >> + if (ei_local->dmaing) { >> + netdev_err(dev, >> + "DMAing conflict in %s " >> + "[DMAstat:%d][irqlock:%d].\n", > > Please don't split error messages, as that makes it more difficult to > grep for them. Again, found like that in ax88796.c. Will fix here (and eventually in ax88796.c). >> + __func__, >> + ei_local->dmaing, ei_local->irqlock); >> + return; > >> +static int xsurf100_probe(struct zorro_dev *zdev, >> + const struct zorro_device_id *ent) >> +{ > >> + /* error handling for ioremap regs */ >> + if (!ax88796_data.base_regs) { >> + dev_err(&zdev->dev, "Cannot ioremap area %p (registers)\n", >> + (void *)zdev->resource.start); > > Please use %pR to format struct resource. > Documentation/core-api/printk-formats.rst The driver uses ioremap to map two subsections of the mem resource for two different purposes - control register access, and ring buffer access. The output of %pR may be misleading here (wrong size), and even more so below. > >> + /* error handling for ioremap data */ >> + if (!ax88796_data.data_area) { >> + dev_err(&zdev->dev, "Cannot ioremap area %p (32-bit access)\n", >> + (void *)zdev->resource.start + XS100_8390_DATA32_BASE); > > %pR I've added the offset into the mem resource here to clarify what we've tried to map. > >> +static void xsurf100_remove(struct zorro_dev *zdev) >> +{ >> + struct platform_device *pdev; >> + struct xsurf100_ax_plat_data *xs100; >> + >> + pdev = zorro_get_drvdata(zdev); >> + xs100 = dev_get_platdata(&pdev->dev); > > struct platform_device *pdev = pdev = zorro_get_drvdata(zdev); > struct xsurf100_ax_plat_data *xs100 = dev_get_platdata(&pdev->dev); Of course. Cheers, Michael > > Gr{oetje,eeting}s, > > Geert > > -- > Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org > > In personal conversations with technical people, I call myself a hacker. But > when I'm talking to journalists I just say "programmer" or something like that. > -- Linus Torvalds
Hi Andrew, On Wed, Apr 18, 2018 at 1:26 AM, Andrew Lunn <andrew@lunn.ch> wrote: > On Tue, Apr 17, 2018 at 02:08:15PM +1200, Michael Schmitz wrote: >> Add platform device driver to populate the ax88796 platform data from >> information provided by the XSurf100 zorro device driver. >> This driver will have to be loaded before loading the ax88796 module, >> or compiled as built-in. >> >> Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> >> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> >> --- >> drivers/net/ethernet/8390/Kconfig | 14 +- >> drivers/net/ethernet/8390/Makefile | 1 + >> drivers/net/ethernet/8390/xsurf100.c | 411 ++++++++++++++++++++++++++++++++++ >> 3 files changed, 425 insertions(+), 1 deletions(-) >> create mode 100644 drivers/net/ethernet/8390/xsurf100.c >> >> diff --git a/drivers/net/ethernet/8390/Kconfig b/drivers/net/ethernet/8390/Kconfig >> index fdc6734..0cadd45 100644 >> --- a/drivers/net/ethernet/8390/Kconfig >> +++ b/drivers/net/ethernet/8390/Kconfig >> @@ -30,7 +30,7 @@ config PCMCIA_AXNET >> >> config AX88796 >> tristate "ASIX AX88796 NE2000 clone support" >> - depends on (ARM || MIPS || SUPERH) >> + depends on (ARM || MIPS || SUPERH || AMIGA) > > Hi Michael > > Will it compile on other platforms? If so, it is a good idea to add > COMPILE_TEST as well. I suppose it will - nothing in there that wouldn't be portable. Well, let's find out, shall we? Cheers, Michael > > Andrew
I think this is a false positive - we're encouraged to provide the
full parameter list for functions, so the sreuct sk_buff* can't be
avoided.
Cheers,
Michael
On Wed, Apr 18, 2018 at 6:46 AM, kbuild test robot <lkp@intel.com> wrote:
> Hi Michael,
>
> I love your patch! Perhaps something to improve:
>
> [auto build test WARNING on v4.16]
> [cannot apply to net-next/master net/master v4.17-rc1 next-20180417]
> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
>
> url: https://github.com/0day-ci/linux/commits/Michael-Schmitz/New-network-driver-for-Amiga-X-Surf-100-m68k/20180417-141150
> config: arm-samsung (attached as .config)
> compiler: arm-linux-gnueabi-gcc (Debian 7.2.0-11) 7.2.0
> reproduce:
> wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
> chmod +x ~/bin/make.cross
> # save the attached .config to linux build tree
> make.cross ARCH=arm
>
> All warnings (new ones prefixed by >>):
>
> In file included from arch/arm/mach-s3c24xx/mach-anubis.c:42:0:
>>> include/net/ax88796.h:35:11: warning: 'struct sk_buff' declared inside parameter list will not be visible outside of this definition or declaration
> struct sk_buff *skb, int ring_offset);
> ^~~~~~~
>
> vim +35 include/net/ax88796.h
>
> 20
> 21 struct ax_plat_data {
> 22 unsigned int flags;
> 23 unsigned char wordlength; /* 1 or 2 */
> 24 unsigned char dcr_val; /* default value for DCR */
> 25 unsigned char rcr_val; /* default value for RCR */
> 26 unsigned char gpoc_val; /* default value for GPOC */
> 27 u32 *reg_offsets; /* register offsets */
> 28 u8 *mac_addr; /* MAC addr (only used when
> 29 AXFLG_MAC_FROMPLATFORM is used */
> 30
> 31 /* uses default ax88796 buffer if set to NULL */
> 32 void (*block_output)(struct net_device *dev, int count,
> 33 const unsigned char *buf, int star_page);
> 34 void (*block_input)(struct net_device *dev, int count,
> > 35 struct sk_buff *skb, int ring_offset);
> 36 };
> 37
>
> ---
> 0-DAY kernel test infrastructure Open Source Technology Center
> https://lists.01.org/pipermail/kbuild-all Intel Corporation
On Wed, Apr 18, 2018 at 12:53:21PM +1200, Michael Schmitz wrote:
> I think this is a false positive - we're encouraged to provide the
> full parameter list for functions, so the sreuct sk_buff* can't be
> avoided.
Hi Michael
How is <linux/skbuff.h> being included?
You probably want to build using the .config file and see.
Andrew
On Wed, 18 Apr 2018, Michael Schmitz wrote: > I think this is a false positive - we're encouraged to provide the > full parameter list for functions, so the sreuct sk_buff* can't be > avoided. > I don't think it's a false positive. I think ax88796.h would need to #include <linux/skbuff.h>. You may be able to get away with a forward declaration, as in, struct skbuff; but I'm not sure about that. I would have to build mach-anubis.c to check. But why do you need to pass an skbuff pointer here? xs100_block_input() only accesses skb->data. BTW, this patch has an unrelated whitespace change. -- > Cheers, > > Michael > > > On Wed, Apr 18, 2018 at 6:46 AM, kbuild test robot <lkp@intel.com> wrote: > > Hi Michael, > > > > I love your patch! Perhaps something to improve: > > > > [auto build test WARNING on v4.16] > > [cannot apply to net-next/master net/master v4.17-rc1 next-20180417] > > [if your patch is applied to the wrong git tree, please drop us a note to help improve the system] > > > > url: https://github.com/0day-ci/linux/commits/Michael-Schmitz/New-network-driver-for-Amiga-X-Surf-100-m68k/20180417-141150 > > config: arm-samsung (attached as .config) > > compiler: arm-linux-gnueabi-gcc (Debian 7.2.0-11) 7.2.0 > > reproduce: > > wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross > > chmod +x ~/bin/make.cross > > # save the attached .config to linux build tree > > make.cross ARCH=arm > > > > All warnings (new ones prefixed by >>): > > > > In file included from arch/arm/mach-s3c24xx/mach-anubis.c:42:0: > >>> include/net/ax88796.h:35:11: warning: 'struct sk_buff' declared inside parameter list will not be visible outside of this definition or declaration > > struct sk_buff *skb, int ring_offset); > > ^~~~~~~ > > > > vim +35 include/net/ax88796.h > > > > 20 > > 21 struct ax_plat_data { > > 22 unsigned int flags; > > 23 unsigned char wordlength; /* 1 or 2 */ > > 24 unsigned char dcr_val; /* default value for DCR */ > > 25 unsigned char rcr_val; /* default value for RCR */ > > 26 unsigned char gpoc_val; /* default value for GPOC */ > > 27 u32 *reg_offsets; /* register offsets */ > > 28 u8 *mac_addr; /* MAC addr (only used when > > 29 AXFLG_MAC_FROMPLATFORM is used */ > > 30 > > 31 /* uses default ax88796 buffer if set to NULL */ > > 32 void (*block_output)(struct net_device *dev, int count, > > 33 const unsigned char *buf, int star_page); > > 34 void (*block_input)(struct net_device *dev, int count, > > > 35 struct sk_buff *skb, int ring_offset); > > 36 }; > > 37 > > > > --- > > 0-DAY kernel test infrastructure Open Source Technology Center > > https://lists.01.org/pipermail/kbuild-all Intel Corporation > -- > To unsubscribe from this list: send the line "unsubscribe linux-m68k" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html >
Hi Andrew,
ax88796 includes it via linux/netdevice.h. mac-anubis.c doesn't.
Michael Karcher's patches have added forward derclarations for struct
netdevice and struct platform_data already - I'll add struct sk_buff
as suggested by Finn.
Cheers,
Michael
On Wed, Apr 18, 2018 at 1:19 PM, Andrew Lunn <andrew@lunn.ch> wrote:
> On Wed, Apr 18, 2018 at 12:53:21PM +1200, Michael Schmitz wrote:
>> I think this is a false positive - we're encouraged to provide the
>> full parameter list for functions, so the sreuct sk_buff* can't be
>> avoided.
>
> Hi Michael
>
> How is <linux/skbuff.h> being included?
>
> You probably want to build using the .config file and see.
>
> Andrew
Hi Finn, On Wed, Apr 18, 2018 at 1:23 PM, Finn Thain <fthain@telegraphics.com.au> wrote: > On Wed, 18 Apr 2018, Michael Schmitz wrote: > >> I think this is a false positive - we're encouraged to provide the >> full parameter list for functions, so the sreuct sk_buff* can't be >> avoided. >> > > I don't think it's a false positive. I think ax88796.h would need to > #include <linux/skbuff.h>. > > You may be able to get away with a forward declaration, as in, > struct skbuff; > but I'm not sure about that. I would have to build mach-anubis.c to check. I've added a forward declaration for now - worked for struct net_device as well (would have been missing from the mach-anubis.c build as well because of the missing netdevice header). > But why do you need to pass an skbuff pointer here? xs100_block_input() > only accesses skb->data. I'm forced to use the same interface as ax_block_input() (xs100_block_input is a plug-in replacement for that). But both could be changed. Let's leave that for later please. > BTW, this patch has an unrelated whitespace change. Fixed, thanks. Cheers, Michael > > -- > >> Cheers, >> >> Michael >> >> >> On Wed, Apr 18, 2018 at 6:46 AM, kbuild test robot <lkp@intel.com> wrote: >> > Hi Michael, >> > >> > I love your patch! Perhaps something to improve: >> > >> > [auto build test WARNING on v4.16] >> > [cannot apply to net-next/master net/master v4.17-rc1 next-20180417] >> > [if your patch is applied to the wrong git tree, please drop us a note to help improve the system] >> > >> > url: https://github.com/0day-ci/linux/commits/Michael-Schmitz/New-network-driver-for-Amiga-X-Surf-100-m68k/20180417-141150 >> > config: arm-samsung (attached as .config) >> > compiler: arm-linux-gnueabi-gcc (Debian 7.2.0-11) 7.2.0 >> > reproduce: >> > wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross >> > chmod +x ~/bin/make.cross >> > # save the attached .config to linux build tree >> > make.cross ARCH=arm >> > >> > All warnings (new ones prefixed by >>): >> > >> > In file included from arch/arm/mach-s3c24xx/mach-anubis.c:42:0: >> >>> include/net/ax88796.h:35:11: warning: 'struct sk_buff' declared inside parameter list will not be visible outside of this definition or declaration >> > struct sk_buff *skb, int ring_offset); >> > ^~~~~~~ >> > >> > vim +35 include/net/ax88796.h >> > >> > 20 >> > 21 struct ax_plat_data { >> > 22 unsigned int flags; >> > 23 unsigned char wordlength; /* 1 or 2 */ >> > 24 unsigned char dcr_val; /* default value for DCR */ >> > 25 unsigned char rcr_val; /* default value for RCR */ >> > 26 unsigned char gpoc_val; /* default value for GPOC */ >> > 27 u32 *reg_offsets; /* register offsets */ >> > 28 u8 *mac_addr; /* MAC addr (only used when >> > 29 AXFLG_MAC_FROMPLATFORM is used */ >> > 30 >> > 31 /* uses default ax88796 buffer if set to NULL */ >> > 32 void (*block_output)(struct net_device *dev, int count, >> > 33 const unsigned char *buf, int star_page); >> > 34 void (*block_input)(struct net_device *dev, int count, >> > > 35 struct sk_buff *skb, int ring_offset); >> > 36 }; >> > 37 >> > >> > --- >> > 0-DAY kernel test infrastructure Open Source Technology Center >> > https://lists.01.org/pipermail/kbuild-all Intel Corporation >> -- >> To unsubscribe from this list: send the line "unsubscribe linux-m68k" in >> the body of a message to majordomo@vger.kernel.org >> More majordomo info at http://vger.kernel.org/majordomo-info.html >> > -- > To unsubscribe from this list: send the line "unsubscribe linux-m68k" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html
This patch series adds support for the Individual Computers X-Surf 100 network card for m68k Amiga, a network adapter based on the AX88796 chip set. The driver was originally written for kernel version 3.19 by Michael Karcher (see CC:), and adapted to 4.16 for submission to netdev by me. Questions regarding motivation for some of the changes are probably best directed at Michael Karcher. The driver has been tested by Adrian <glaubitz@physik.fu-berlin.de> who will send his Tested-by tag separately. A few changes to the ax88796 driver were required: - to read the MAC address, some setup of the ax99796 chip must be done, - attach to the MII bus only on device open to allow module unloading, - allow to supersede ax_block_input/ax_block_output by card-specific optimized code, - use an optional interrupt status callback to allow easier sharing of the card interrupt, - set IRQF_SHARED if platform IRQ resource is marked shareable, The Asix Electronix PHY used on the X-Surf 100 is buggy, and causes the software reset to hang if the previous command sent to the PHY was also a soft reset. This bug requires addition of a PHY driver for Asix PHYs to provide a fixed .soft_reset function, included in this series. Some additional cleanup: - do not attempt to free IRQ in ax_remove (complements 82533ad9a1c), - clear platform drvdata on probe fail and module remove. Changes since v1: Raised in review by Andrew Lunn: - move MII code around to avoid need for forward declaration - combine patches 2 and 7 to add cleanup in error path Changes since v2: - corrected authorship attribution to Michael Karcher Suggested by Geert Uytterhoeven: - use ei_local->reset_8390() instead of duplicating ax_reset_8390() - use %pR to format struct resource pointers - assign pdev and xs100 pointers in declaration - don't split error messages - change Kconfig logic to only require XSURF100 set on Amiga Suggested by Andrew Lunn: - add COMPILE_TEST to ax88796 Kconfig options - use new Asix PHY driver for X-Surf 100 Suggested by Andrew Lunn/Finn Thain: - declare struct sk_buff in ax88796.h - correct whitespace error in ax88796.h This series' patches, in order: 1/9 net: phy: new Asix Electronics PHY driver 2/9 net: ax88796: Fix MAC address reading 3/9 net: ax88796: Attach MII bus only when open 4/9 net: ax88796: Do not free IRQ in ax_remove() (already freed in ax_close()). 5/9 net: ax88796: Add block_input/output hooks to ax_plat_data 6/9 net: ax88796: add interrupt status callback to platform data 7/9 net: ax88796: set IRQF_SHARED flag when IRQ resource is marked as shareable 8/9 net: ax88796: release platform device drvdata on probe error and module remove 9/9 net: New ax88796 platform driver for Amiga X-Surf 100 Zorro board (m68k) drivers/net/ethernet/8390/Kconfig | 17 ++- drivers/net/ethernet/8390/Makefile | 1 + drivers/net/ethernet/8390/ax88796.c | 228 ++++++++++++-------- drivers/net/ethernet/8390/xsurf100.c | 381 ++++++++++++++++++++++++++++++++++ drivers/net/phy/Kconfig | 6 + drivers/net/phy/Makefile | 1 + drivers/net/phy/asix.c | 65 ++++++ drivers/net/phy/phy_device.c | 3 +- include/linux/phy.h | 1 + include/net/ax88796.h | 14 ++ 10 files changed, 621 insertions(+), 96 deletions(-) Cheers, Michael
The Asix Electronics PHY found on the X-Surf 100 Amiga Zorro network card by Individual Computers is buggy, and needs the reset bit toggled as workaround to make a PHY soft reset succed. Add workaround driver just for this special case. Export phy_poll_reset() from core phy_device driver to avoid code duplication. Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> --- drivers/net/phy/Kconfig | 6 ++++ drivers/net/phy/Makefile | 1 + drivers/net/phy/asix.c | 65 ++++++++++++++++++++++++++++++++++++++++++ drivers/net/phy/phy_device.c | 3 +- include/linux/phy.h | 1 + 5 files changed, 75 insertions(+), 1 deletions(-) create mode 100644 drivers/net/phy/asix.c diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index bdfbabb..f5b484c 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -218,6 +218,12 @@ config AQUANTIA_PHY ---help--- Currently supports the Aquantia AQ1202, AQ2104, AQR105, AQR405 +config ASIX_PHY + tristate "Asix PHYs" + ---help--- + Currently supports the Asix Electronics PHY found in the X-Surf 100 + AX88796 package. + config AT803X_PHY tristate "AT803X PHYs" ---help--- diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 01acbcb..701ca0b 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -45,6 +45,7 @@ obj-y += $(sfp-obj-y) $(sfp-obj-m) obj-$(CONFIG_AMD_PHY) += amd.o obj-$(CONFIG_AQUANTIA_PHY) += aquantia.o +obj-$(CONFIG_ASIX_PHY) += asix.o obj-$(CONFIG_AT803X_PHY) += at803x.o obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o obj-$(CONFIG_BCM7XXX_PHY) += bcm7xxx.o diff --git a/drivers/net/phy/asix.c b/drivers/net/phy/asix.c new file mode 100644 index 0000000..15e8a0e --- /dev/null +++ b/drivers/net/phy/asix.c @@ -0,0 +1,65 @@ +/* + * Driver for Asix PHYs + * + * Author: Michael Schmitz <schmitzmic@gmail.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/mii.h> +#include <linux/phy.h> + +#define PHY_ID_ASIX 0x003b1841 + +MODULE_DESCRIPTION("Asix PHY driver"); +MODULE_AUTHOR("Michael Schmitz <schmitzmic@gmail.com>"); +MODULE_LICENSE("GPL"); + +/** + * asix_soft_reset - software reset the PHY via BMCR_RESET bit + * @phydev: target phy_device struct + * + * Description: Perform a software PHY reset using the standard + * BMCR_RESET bit and poll for the reset bit to be cleared. + * Toggle BMCR_RESET bit off to accomodate broken PHY implementations + * such as used on the Individual Computers' X-Surf 100 Zorro card. + * + * Returns: 0 on success, < 0 on failure + */ +static int asix_soft_reset(struct phy_device *phydev) +{ + int ret; + + /* Asix PHY won't reset unless reset bit toggles */ + ret = phy_write(phydev, MII_BMCR, 0); + if (ret < 0) + return ret; + + phy_write(phydev, MII_BMCR, BMCR_RESET); + + return phy_poll_reset(phydev); +} + +static struct phy_driver asix_driver[] = { { + .phy_id = PHY_ID_ASIX, + .name = "Asix Electronics", + .phy_id_mask = 0xfffffff0, + .features = PHY_BASIC_FEATURES, + .soft_reset = asix_soft_reset, +} }; + +module_phy_driver(asix_driver); + +static struct mdio_device_id __maybe_unused asix_tbl[] = { + { PHY_ID_ASIX, 0xfffffff0 }, + { } +}; + +MODULE_DEVICE_TABLE(mdio, asix_tbl); diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 777912b..fb8c13b 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -833,7 +833,7 @@ void phy_disconnect(struct phy_device *phydev) * standard phy_init_hw() which will zero all the other bits in the BMCR * and reapply all driver-specific and board-specific fixups. */ -static int phy_poll_reset(struct phy_device *phydev) +int phy_poll_reset(struct phy_device *phydev) { /* Poll until the reset bit clears (50ms per retry == 0.6 sec) */ unsigned int retries = 12; @@ -854,6 +854,7 @@ static int phy_poll_reset(struct phy_device *phydev) msleep(1); return 0; } +EXPORT_SYMBOL(phy_poll_reset); int phy_init_hw(struct phy_device *phydev) { diff --git a/include/linux/phy.h b/include/linux/phy.h index 7c4c237..fa0c4fd 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -980,6 +980,7 @@ void phy_attached_print(struct phy_device *phydev, const char *fmt, ...) int genphy_resume(struct phy_device *phydev); int genphy_loopback(struct phy_device *phydev, bool enable); int genphy_soft_reset(struct phy_device *phydev); +int phy_poll_reset(struct phy_device *phydev); static inline int genphy_no_soft_reset(struct phy_device *phydev) { return 0; -- 1.7.0.4
From: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> To read the MAC address from the (virtual) SAprom, the remote DMA unit needs to be set up like for every other process access to card-local memory. Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> --- drivers/net/ethernet/8390/ax88796.c | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index 2455547..2a256aa 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -671,10 +671,16 @@ static int ax_init_dev(struct net_device *dev) if (ax->plat->flags & AXFLG_HAS_EEPROM) { unsigned char SA_prom[32]; + ei_outb(6, ioaddr + EN0_RCNTLO); + ei_outb(0, ioaddr + EN0_RCNTHI); + ei_outb(0, ioaddr + EN0_RSARLO); + ei_outb(0, ioaddr + EN0_RSARHI); + ei_outb(E8390_RREAD + E8390_START, ioaddr + NE_CMD); for (i = 0; i < sizeof(SA_prom); i += 2) { SA_prom[i] = ei_inb(ioaddr + NE_DATAPORT); SA_prom[i + 1] = ei_inb(ioaddr + NE_DATAPORT); } + ei_outb(ENISR_RDC, ioaddr + EN0_ISR); /* Ack intr. */ if (ax->plat->wordlength == 2) for (i = 0; i < 16; i++) -- 1.7.0.4
From: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Call ax_mii_init in ax_open(), and unregister/remove mdiobus resources in ax_close(). This is needed to be able to unload the module, as the module is busy while the MII bus is attached. Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> Reviewed-by: Andrew Lunn <andrew@lunn.ch> --- drivers/net/ethernet/8390/ax88796.c | 183 ++++++++++++++++++----------------- 1 files changed, 95 insertions(+), 88 deletions(-) diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index 2a256aa..83e59ae 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -389,6 +389,90 @@ static void ax_phy_switch(struct net_device *dev, int on) ei_outb(reg_gpoc, ei_local->mem + EI_SHIFT(0x17)); } +static void ax_bb_mdc(struct mdiobb_ctrl *ctrl, int level) +{ + struct ax_device *ax = container_of(ctrl, struct ax_device, bb_ctrl); + + if (level) + ax->reg_memr |= AX_MEMR_MDC; + else + ax->reg_memr &= ~AX_MEMR_MDC; + + ei_outb(ax->reg_memr, ax->addr_memr); +} + +static void ax_bb_dir(struct mdiobb_ctrl *ctrl, int output) +{ + struct ax_device *ax = container_of(ctrl, struct ax_device, bb_ctrl); + + if (output) + ax->reg_memr &= ~AX_MEMR_MDIR; + else + ax->reg_memr |= AX_MEMR_MDIR; + + ei_outb(ax->reg_memr, ax->addr_memr); +} + +static void ax_bb_set_data(struct mdiobb_ctrl *ctrl, int value) +{ + struct ax_device *ax = container_of(ctrl, struct ax_device, bb_ctrl); + + if (value) + ax->reg_memr |= AX_MEMR_MDO; + else + ax->reg_memr &= ~AX_MEMR_MDO; + + ei_outb(ax->reg_memr, ax->addr_memr); +} + +static int ax_bb_get_data(struct mdiobb_ctrl *ctrl) +{ + struct ax_device *ax = container_of(ctrl, struct ax_device, bb_ctrl); + int reg_memr = ei_inb(ax->addr_memr); + + return reg_memr & AX_MEMR_MDI ? 1 : 0; +} + +static const struct mdiobb_ops bb_ops = { + .owner = THIS_MODULE, + .set_mdc = ax_bb_mdc, + .set_mdio_dir = ax_bb_dir, + .set_mdio_data = ax_bb_set_data, + .get_mdio_data = ax_bb_get_data, +}; + +static int ax_mii_init(struct net_device *dev) +{ + struct platform_device *pdev = to_platform_device(dev->dev.parent); + struct ei_device *ei_local = netdev_priv(dev); + struct ax_device *ax = to_ax_dev(dev); + int err; + + ax->bb_ctrl.ops = &bb_ops; + ax->addr_memr = ei_local->mem + AX_MEMR; + ax->mii_bus = alloc_mdio_bitbang(&ax->bb_ctrl); + if (!ax->mii_bus) { + err = -ENOMEM; + goto out; + } + + ax->mii_bus->name = "ax88796_mii_bus"; + ax->mii_bus->parent = dev->dev.parent; + snprintf(ax->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", + pdev->name, pdev->id); + + err = mdiobus_register(ax->mii_bus); + if (err) + goto out_free_mdio_bitbang; + + return 0; + + out_free_mdio_bitbang: + free_mdio_bitbang(ax->mii_bus); + out: + return err; +} + static int ax_open(struct net_device *dev) { struct ax_device *ax = to_ax_dev(dev); @@ -396,6 +480,10 @@ static int ax_open(struct net_device *dev) netdev_dbg(dev, "open\n"); + ret = ax_mii_init(dev); + if (ret) + goto failed_mii; + ret = request_irq(dev->irq, ax_ei_interrupt, ax->irqflags, dev->name, dev); if (ret) @@ -423,6 +511,10 @@ static int ax_open(struct net_device *dev) ax_phy_switch(dev, 0); free_irq(dev->irq, dev); failed_request_irq: + /* unregister mdiobus */ + mdiobus_unregister(ax->mii_bus); + free_mdio_bitbang(ax->mii_bus); + failed_mii: return ret; } @@ -442,6 +534,9 @@ static int ax_close(struct net_device *dev) phy_disconnect(dev->phydev); free_irq(dev->irq, dev); + + mdiobus_unregister(ax->mii_bus); + free_mdio_bitbang(ax->mii_bus); return 0; } @@ -541,92 +636,8 @@ static void ax_eeprom_register_write(struct eeprom_93cx6 *eeprom) #endif }; -static void ax_bb_mdc(struct mdiobb_ctrl *ctrl, int level) -{ - struct ax_device *ax = container_of(ctrl, struct ax_device, bb_ctrl); - - if (level) - ax->reg_memr |= AX_MEMR_MDC; - else - ax->reg_memr &= ~AX_MEMR_MDC; - - ei_outb(ax->reg_memr, ax->addr_memr); -} - -static void ax_bb_dir(struct mdiobb_ctrl *ctrl, int output) -{ - struct ax_device *ax = container_of(ctrl, struct ax_device, bb_ctrl); - - if (output) - ax->reg_memr &= ~AX_MEMR_MDIR; - else - ax->reg_memr |= AX_MEMR_MDIR; - - ei_outb(ax->reg_memr, ax->addr_memr); -} - -static void ax_bb_set_data(struct mdiobb_ctrl *ctrl, int value) -{ - struct ax_device *ax = container_of(ctrl, struct ax_device, bb_ctrl); - - if (value) - ax->reg_memr |= AX_MEMR_MDO; - else - ax->reg_memr &= ~AX_MEMR_MDO; - - ei_outb(ax->reg_memr, ax->addr_memr); -} - -static int ax_bb_get_data(struct mdiobb_ctrl *ctrl) -{ - struct ax_device *ax = container_of(ctrl, struct ax_device, bb_ctrl); - int reg_memr = ei_inb(ax->addr_memr); - - return reg_memr & AX_MEMR_MDI ? 1 : 0; -} - -static const struct mdiobb_ops bb_ops = { - .owner = THIS_MODULE, - .set_mdc = ax_bb_mdc, - .set_mdio_dir = ax_bb_dir, - .set_mdio_data = ax_bb_set_data, - .get_mdio_data = ax_bb_get_data, -}; - /* setup code */ -static int ax_mii_init(struct net_device *dev) -{ - struct platform_device *pdev = to_platform_device(dev->dev.parent); - struct ei_device *ei_local = netdev_priv(dev); - struct ax_device *ax = to_ax_dev(dev); - int err; - - ax->bb_ctrl.ops = &bb_ops; - ax->addr_memr = ei_local->mem + AX_MEMR; - ax->mii_bus = alloc_mdio_bitbang(&ax->bb_ctrl); - if (!ax->mii_bus) { - err = -ENOMEM; - goto out; - } - - ax->mii_bus->name = "ax88796_mii_bus"; - ax->mii_bus->parent = dev->dev.parent; - snprintf(ax->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", - pdev->name, pdev->id); - - err = mdiobus_register(ax->mii_bus); - if (err) - goto out_free_mdio_bitbang; - - return 0; - - out_free_mdio_bitbang: - free_mdio_bitbang(ax->mii_bus); - out: - return err; -} - static void ax_initial_setup(struct net_device *dev, struct ei_device *ei_local) { void __iomem *ioaddr = ei_local->mem; @@ -758,10 +769,6 @@ static int ax_init_dev(struct net_device *dev) dev->netdev_ops = &ax_netdev_ops; dev->ethtool_ops = &ax_ethtool_ops; - ret = ax_mii_init(dev); - if (ret) - goto err_out; - ax_NS8390_init(dev, 0); ret = register_netdev(dev); -- 1.7.0.4
From: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> This complements the fix in 82533ad9a1c ("net: ethernet: ax88796: don't call free_irq without request_irq first") that removed the free_irq call in the error path of probe, to also not call free_irq when remove is called to revert the effects of probe. Fixes: 82533ad9a1c (net: ethernet: ax88796: don't call free_irq without request_irq first) Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> Reviewed-by: Geert Uytterhoeven <geert@linux-m68k.org> --- drivers/net/ethernet/8390/ax88796.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index 83e59ae..ecf104c 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -793,7 +793,6 @@ static int ax_remove(struct platform_device *pdev) struct resource *mem; unregister_netdev(dev); - free_irq(dev->irq, dev); iounmap(ei_local->mem); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- 1.7.0.4
From: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Add platform specific hooks for block transfer reads/writes of packet buffer data, superseding the default provided ax_block_input/output. Currently used for m68k Amiga XSurf100. Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> --- Changes in v3: Suggested by Andrew Lunn/Finn Thain: - declare struct sk_buff in ax88796.h - correct whitespace error --- drivers/net/ethernet/8390/ax88796.c | 10 ++++++++-- include/net/ax88796.h | 9 +++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index ecf104c..29cde38 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -760,8 +760,14 @@ static int ax_init_dev(struct net_device *dev) #endif ei_local->reset_8390 = &ax_reset_8390; - ei_local->block_input = &ax_block_input; - ei_local->block_output = &ax_block_output; + if (ax->plat->block_input) + ei_local->block_input = ax->plat->block_input; + else + ei_local->block_input = &ax_block_input; + if (ax->plat->block_output) + ei_local->block_output = ax->plat->block_output; + else + ei_local->block_output = &ax_block_output; ei_local->get_8390_hdr = &ax_get_8390_hdr; ei_local->priv = 0; ei_local->msg_enable = ax_msg_enable; diff --git a/include/net/ax88796.h b/include/net/ax88796.h index b9a3bec..363b0ca 100644 --- a/include/net/ax88796.h +++ b/include/net/ax88796.h @@ -12,6 +12,9 @@ #ifndef __NET_AX88796_PLAT_H #define __NET_AX88796_PLAT_H +struct sk_buff; +struct net_device; + #define AXFLG_HAS_EEPROM (1<<0) #define AXFLG_MAC_FROMDEV (1<<1) /* device already has MAC */ #define AXFLG_HAS_93CX6 (1<<2) /* use eeprom_93cx6 driver */ @@ -26,6 +29,12 @@ struct ax_plat_data { u32 *reg_offsets; /* register offsets */ u8 *mac_addr; /* MAC addr (only used when AXFLG_MAC_FROMPLATFORM is used */ + + /* uses default ax88796 buffer if set to NULL */ + void (*block_output)(struct net_device *dev, int count, + const unsigned char *buf, int star_page); + void (*block_input)(struct net_device *dev, int count, + struct sk_buff *skb, int ring_offset); }; #endif /* __NET_AX88796_PLAT_H */ -- 1.7.0.4
From: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> To be able to tell the ax88796 driver whether it is sensible to enter the 8390 interrupt handler, an "is this interrupt caused by the 88796" callback has been added to the ax_plat_data structure (with NULL being compatible to the previous behaviour). Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> --- drivers/net/ethernet/8390/ax88796.c | 23 +++++++++++++++++++++-- include/net/ax88796.h | 5 +++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index 29cde38..c799441 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -165,6 +165,21 @@ static void ax_reset_8390(struct net_device *dev) ei_outb(ENISR_RESET, addr + EN0_ISR); /* Ack intr. */ } +/* Wrapper for __ei_interrupt for platforms that have a platform-specific + * way to find out whether the interrupt request might be caused by + * the ax88796 chip. + */ +static irqreturn_t ax_ei_interrupt_filtered(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct ax_device *ax = to_ax_dev(dev); + struct platform_device *pdev = to_platform_device(dev->dev.parent); + + if (!ax->plat->check_irq(pdev)) + return IRQ_NONE; + + return ax_ei_interrupt(irq, dev_id); +} static void ax_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page) @@ -484,8 +499,12 @@ static int ax_open(struct net_device *dev) if (ret) goto failed_mii; - ret = request_irq(dev->irq, ax_ei_interrupt, ax->irqflags, - dev->name, dev); + if (ax->plat->check_irq) + ret = request_irq(dev->irq, ax_ei_interrupt_filtered, + ax->irqflags, dev->name, dev); + else + ret = request_irq(dev->irq, ax_ei_interrupt, ax->irqflags, + dev->name, dev); if (ret) goto failed_request_irq; diff --git a/include/net/ax88796.h b/include/net/ax88796.h index 363b0ca..84b3785 100644 --- a/include/net/ax88796.h +++ b/include/net/ax88796.h @@ -14,6 +14,7 @@ struct sk_buff; struct net_device; +struct platform_device; #define AXFLG_HAS_EEPROM (1<<0) #define AXFLG_MAC_FROMDEV (1<<1) /* device already has MAC */ @@ -35,6 +36,10 @@ struct ax_plat_data { const unsigned char *buf, int star_page); void (*block_input)(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset); + /* returns nonzero if a pending interrupt request might by caused by + * the ax88786. Handles all interrupts if set to NULL + */ + int (*check_irq)(struct platform_device *pdev); }; #endif /* __NET_AX88796_PLAT_H */ -- 1.7.0.4
From: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> On the Amiga X-Surf100, the network card interrupt is shared with many other interrupt sources, so requires the IRQF_SHARED flag to register. Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> --- drivers/net/ethernet/8390/ax88796.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index c799441..a72dfbc 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -875,6 +875,9 @@ static int ax_probe(struct platform_device *pdev) dev->irq = irq->start; ax->irqflags = irq->flags & IRQF_TRIGGER_MASK; + if (irq->flags & IORESOURCE_IRQ_SHAREABLE) + ax->irqflags |= IRQF_SHARED; + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) { dev_err(&pdev->dev, "no MEM specified\n"); -- 1.7.0.4
The net device struct pointer is stored as platform device drvdata on module probe - clear the drvdata entry on probe fail there, as well as when unloading the module. Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> --- drivers/net/ethernet/8390/ax88796.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index a72dfbc..eb72282 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -829,6 +829,7 @@ static int ax_remove(struct platform_device *pdev) release_mem_region(mem->start, resource_size(mem)); } + platform_set_drvdata(pdev, NULL); free_netdev(dev); return 0; @@ -962,6 +963,7 @@ static int ax_probe(struct platform_device *pdev) release_mem_region(mem->start, mem_size); exit_mem: + platform_set_drvdata(pdev, NULL); free_netdev(dev); return ret; -- 1.7.0.4
From: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Add platform device driver to populate the ax88796 platform data from information provided by the XSurf100 zorro device driver. The ax88796 module will be loaded through this module's probe function. Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> --- Changes in v3: Suggested by Geert Uytterhoeven: - use ei_local->reset_8390() instead of duplicating ax_reset_8390() - use %pR to format struct resource pointers - assign pdev and xs100 pointers in declaration - don't split error messages - change Kconfig logic to only require XSURF100 set on Amiga Suggested by Andrew Lunn: - add COMPILE_TEST to ax88796 Kconfig options - use new Asix PHY driver for X-Surf 100 --- drivers/net/ethernet/8390/Kconfig | 17 ++- drivers/net/ethernet/8390/Makefile | 1 + drivers/net/ethernet/8390/xsurf100.c | 381 ++++++++++++++++++++++++++++++++++ 3 files changed, 397 insertions(+), 2 deletions(-) create mode 100644 drivers/net/ethernet/8390/xsurf100.c diff --git a/drivers/net/ethernet/8390/Kconfig b/drivers/net/ethernet/8390/Kconfig index fdc6734..607dc00 100644 --- a/drivers/net/ethernet/8390/Kconfig +++ b/drivers/net/ethernet/8390/Kconfig @@ -29,8 +29,8 @@ config PCMCIA_AXNET called axnet_cs. If unsure, say N. config AX88796 - tristate "ASIX AX88796 NE2000 clone support" - depends on (ARM || MIPS || SUPERH) + tristate "ASIX AX88796 NE2000 clone support" if !ZORRO + depends on (ARM || MIPS || SUPERH || ZORRO || COMPILE_TEST) select CRC32 select PHYLIB select MDIO_BITBANG @@ -45,6 +45,19 @@ config AX88796_93CX6 ---help--- Select this if your platform comes with an external 93CX6 eeprom. +config XSURF100 + tristate "Amiga XSurf 100 AX88796/NE2000 clone support" + depends on ZORRO + select AX88796 + select ASIX_PHY + ---help--- + This driver is for the Individual Computers X-Surf 100 Ethernet + card (based on the Asix AX88796 chip). If you have such a card, + say Y. Otherwise, say N. + + To compile this driver as a module, choose M here: the module + will be called xsurf100. + config HYDRA tristate "Hydra support" depends on ZORRO diff --git a/drivers/net/ethernet/8390/Makefile b/drivers/net/ethernet/8390/Makefile index f975c2f..3715f8d 100644 --- a/drivers/net/ethernet/8390/Makefile +++ b/drivers/net/ethernet/8390/Makefile @@ -16,4 +16,5 @@ obj-$(CONFIG_PCMCIA_PCNET) += pcnet_cs.o 8390.o obj-$(CONFIG_STNIC) += stnic.o 8390.o obj-$(CONFIG_ULTRA) += smc-ultra.o 8390.o obj-$(CONFIG_WD80x3) += wd.o 8390.o +obj-$(CONFIG_XSURF100) += xsurf100.o obj-$(CONFIG_ZORRO8390) += zorro8390.o 8390.o diff --git a/drivers/net/ethernet/8390/xsurf100.c b/drivers/net/ethernet/8390/xsurf100.c new file mode 100644 index 0000000..7ab5ca0 --- /dev/null +++ b/drivers/net/ethernet/8390/xsurf100.c @@ -0,0 +1,381 @@ +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/platform_device.h> +#include <linux/zorro.h> +#include <net/ax88796.h> +#include <asm/amigaints.h> + +#define ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF100 \ + ZORRO_ID(INDIVIDUAL_COMPUTERS, 0x64, 0) + +#define XS100_IRQSTATUS_BASE 0x40 +#define XS100_8390_BASE 0x800 + +/* Longword-access area. Translated to 2 16-bit access cycles by the + * X-Surf 100 FPGA + */ +#define XS100_8390_DATA32_BASE 0x8000 +#define XS100_8390_DATA32_SIZE 0x2000 +/* Sub-Areas for fast data register access; addresses relative to area begin */ +#define XS100_8390_DATA_READ32_BASE 0x0880 +#define XS100_8390_DATA_WRITE32_BASE 0x0C80 +#define XS100_8390_DATA_AREA_SIZE 0x80 + +#define __NS8390_init ax_NS8390_init + +/* force unsigned long back to 'void __iomem *' */ +#define ax_convert_addr(_a) ((void __force __iomem *)(_a)) + +#define ei_inb(_a) z_readb(ax_convert_addr(_a)) +#define ei_outb(_v, _a) z_writeb(_v, ax_convert_addr(_a)) + +#define ei_inw(_a) z_readw(ax_convert_addr(_a)) +#define ei_outw(_v, _a) z_writew(_v, ax_convert_addr(_a)) + +#define ei_inb_p(_a) ei_inb(_a) +#define ei_outb_p(_v, _a) ei_outb(_v, _a) + +/* define EI_SHIFT() to take into account our register offsets */ +#define EI_SHIFT(x) (ei_local->reg_offset[(x)]) + +/* Ensure we have our RCR base value */ +#define AX88796_PLATFORM + +static unsigned char version[] = + "ax88796.c: Copyright 2005,2007 Simtec Electronics\n"; + +#include "lib8390.c" + +/* from ne.c */ +#define NE_CMD EI_SHIFT(0x00) +#define NE_RESET EI_SHIFT(0x1f) +#define NE_DATAPORT EI_SHIFT(0x10) + +struct xsurf100_ax_plat_data { + struct ax_plat_data ax; + void __iomem *base_regs; + void __iomem *data_area; +}; + +static int is_xsurf100_network_irq(struct platform_device *pdev) +{ + struct xsurf100_ax_plat_data *xs100 = dev_get_platdata(&pdev->dev); + + return (readw(xs100->base_regs + XS100_IRQSTATUS_BASE) & 0xaaaa) != 0; +} + +/* These functions guarantee that the iomem is accessed with 32 bit + * cycles only. z_memcpy_fromio / z_memcpy_toio don't + */ +static void z_memcpy_fromio32(void *dst, const void __iomem *src, size_t bytes) +{ + while (bytes > 32) { + asm __volatile__ + ("movem.l (%0)+,%%d0-%%d7\n" + "movem.l %%d0-%%d7,(%1)\n" + "adda.l #32,%1" : "=a"(src), "=a"(dst) + : "0"(src), "1"(dst) : "d0", "d1", "d2", "d3", "d4", + "d5", "d6", "d7", "memory"); + bytes -= 32; + } + while (bytes) { + *(uint32_t *)dst = z_readl(src); + src += 4; + dst += 4; + bytes -= 4; + } +} + +static void z_memcpy_toio32(void __iomem *dst, const void *src, size_t bytes) +{ + while (bytes) { + z_writel(*(const uint32_t *)src, dst); + src += 4; + dst += 4; + bytes -= 4; + } +} + +static void xs100_write(struct net_device *dev, const void *src, + unsigned int count) +{ + struct ei_device *ei_local = netdev_priv(dev); + struct platform_device *pdev = to_platform_device(dev->dev.parent); + struct xsurf100_ax_plat_data *xs100 = dev_get_platdata(&pdev->dev); + + /* copy whole blocks */ + while (count > XS100_8390_DATA_AREA_SIZE) { + z_memcpy_toio32(xs100->data_area + + XS100_8390_DATA_WRITE32_BASE, src, + XS100_8390_DATA_AREA_SIZE); + src += XS100_8390_DATA_AREA_SIZE; + count -= XS100_8390_DATA_AREA_SIZE; + } + /* copy whole dwords */ + z_memcpy_toio32(xs100->data_area + XS100_8390_DATA_WRITE32_BASE, + src, count & ~3); + src += count & ~3; + if (count & 2) { + ei_outw(*(uint16_t *)src, ei_local->mem + NE_DATAPORT); + src += 2; + } + if (count & 1) + ei_outb(*(uint8_t *)src, ei_local->mem + NE_DATAPORT); +} + +static void xs100_read(struct net_device *dev, void *dst, unsigned int count) +{ + struct ei_device *ei_local = netdev_priv(dev); + struct platform_device *pdev = to_platform_device(dev->dev.parent); + struct xsurf100_ax_plat_data *xs100 = dev_get_platdata(&pdev->dev); + + /* copy whole blocks */ + while (count > XS100_8390_DATA_AREA_SIZE) { + z_memcpy_fromio32(dst, xs100->data_area + + XS100_8390_DATA_READ32_BASE, + XS100_8390_DATA_AREA_SIZE); + dst += XS100_8390_DATA_AREA_SIZE; + count -= XS100_8390_DATA_AREA_SIZE; + } + /* copy whole dwords */ + z_memcpy_fromio32(dst, xs100->data_area + XS100_8390_DATA_READ32_BASE, + count & ~3); + dst += count & ~3; + if (count & 2) { + *(uint16_t *)dst = ei_inw(ei_local->mem + NE_DATAPORT); + dst += 2; + } + if (count & 1) + *(uint8_t *)dst = ei_inb(ei_local->mem + NE_DATAPORT); +} + +/* Block input and output, similar to the Crynwr packet driver. If + * you are porting to a new ethercard, look at the packet driver + * source for hints. The NEx000 doesn't share the on-board packet + * memory -- you have to put the packet out through the "remote DMA" + * dataport using ei_outb. + */ +static void xs100_block_input(struct net_device *dev, int count, + struct sk_buff *skb, int ring_offset) +{ + struct ei_device *ei_local = netdev_priv(dev); + void __iomem *nic_base = ei_local->mem; + char *buf = skb->data; + + if (ei_local->dmaing) { + netdev_err(dev, + "DMAing conflict in %s [DMAstat:%d][irqlock:%d]\n", + __func__, + ei_local->dmaing, ei_local->irqlock); + return; + } + + ei_local->dmaing |= 0x01; + + ei_outb(E8390_NODMA + E8390_PAGE0 + E8390_START, nic_base + NE_CMD); + ei_outb(count & 0xff, nic_base + EN0_RCNTLO); + ei_outb(count >> 8, nic_base + EN0_RCNTHI); + ei_outb(ring_offset & 0xff, nic_base + EN0_RSARLO); + ei_outb(ring_offset >> 8, nic_base + EN0_RSARHI); + ei_outb(E8390_RREAD + E8390_START, nic_base + NE_CMD); + + xs100_read(dev, buf, count); + + ei_local->dmaing &= ~1; +} + +static void xs100_block_output(struct net_device *dev, int count, + const unsigned char *buf, const int start_page) +{ + struct ei_device *ei_local = netdev_priv(dev); + void __iomem *nic_base = ei_local->mem; + unsigned long dma_start; + + /* Round the count up for word writes. Do we need to do this? + * What effect will an odd byte count have on the 8390? I + * should check someday. + */ + if (ei_local->word16 && (count & 0x01)) + count++; + + /* This *shouldn't* happen. If it does, it's the last thing + * you'll see + */ + if (ei_local->dmaing) { + netdev_err(dev, + "DMAing conflict in %s [DMAstat:%d][irqlock:%d]\n", + __func__, + ei_local->dmaing, ei_local->irqlock); + return; + } + + ei_local->dmaing |= 0x01; + /* We should already be in page 0, but to be safe... */ + ei_outb(E8390_PAGE0 + E8390_START + E8390_NODMA, nic_base + NE_CMD); + + ei_outb(ENISR_RDC, nic_base + EN0_ISR); + + /* Now the normal output. */ + ei_outb(count & 0xff, nic_base + EN0_RCNTLO); + ei_outb(count >> 8, nic_base + EN0_RCNTHI); + ei_outb(0x00, nic_base + EN0_RSARLO); + ei_outb(start_page, nic_base + EN0_RSARHI); + + ei_outb(E8390_RWRITE + E8390_START, nic_base + NE_CMD); + + xs100_write(dev, buf, count); + + dma_start = jiffies; + + while ((ei_inb(nic_base + EN0_ISR) & ENISR_RDC) == 0) { + if (jiffies - dma_start > 2 * HZ / 100) { /* 20ms */ + netdev_warn(dev, "timeout waiting for Tx RDC.\n"); + ei_local->reset_8390(dev); + ax_NS8390_init(dev, 1); + break; + } + } + + ei_outb(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ + ei_local->dmaing &= ~0x01; +} + +static int xsurf100_probe(struct zorro_dev *zdev, + const struct zorro_device_id *ent) +{ + struct platform_device *pdev; + struct xsurf100_ax_plat_data ax88796_data; + struct resource res[2] = { + DEFINE_RES_NAMED(IRQ_AMIGA_PORTS, 1, NULL, + IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE), + DEFINE_RES_MEM(zdev->resource.start + XS100_8390_BASE, + 4 * 0x20) + }; + int reg; + /* This table is referenced in the device structure, so it must + * outlive the scope of xsurf100_probe. + */ + static u32 reg_offsets[32]; + int ret = 0; + + /* X-Surf 100 control and 32 bit ring buffer data access areas. + * These resources are not used by the ax88796 driver, so must + * be requested here and passed via platform data. + */ + + if (!request_mem_region(zdev->resource.start, 0x100, zdev->name)) { + dev_err(&zdev->dev, "cannot reserve X-Surf 100 control registers\n"); + return -ENXIO; + } + + if (!request_mem_region(zdev->resource.start + + XS100_8390_DATA32_BASE, + XS100_8390_DATA32_SIZE, + "X-Surf 100 32-bit data access")) { + dev_err(&zdev->dev, "cannot reserve 32-bit area\n"); + ret = -ENXIO; + goto exit_req; + } + + for (reg = 0; reg < 0x20; reg++) + reg_offsets[reg] = 4 * reg; + + memset(&ax88796_data, 0, sizeof(ax88796_data)); + ax88796_data.ax.flags = AXFLG_HAS_EEPROM; + ax88796_data.ax.wordlength = 2; + ax88796_data.ax.dcr_val = 0x48; + ax88796_data.ax.rcr_val = 0x40; + ax88796_data.ax.reg_offsets = reg_offsets; + ax88796_data.ax.check_irq = is_xsurf100_network_irq; + ax88796_data.base_regs = ioremap(zdev->resource.start, 0x100); + + /* error handling for ioremap regs */ + if (!ax88796_data.base_regs) { + dev_err(&zdev->dev, "Cannot ioremap area %pR (registers)\n", + &zdev->resource); + + ret = -ENXIO; + goto exit_req2; + } + + ax88796_data.data_area = ioremap(zdev->resource.start + + XS100_8390_DATA32_BASE, XS100_8390_DATA32_SIZE); + + /* error handling for ioremap data */ + if (!ax88796_data.data_area) { + dev_err(&zdev->dev, + "Cannot ioremap area %pR offset %x (32-bit access)\n", + &zdev->resource, XS100_8390_DATA32_BASE); + + ret = -ENXIO; + goto exit_mem; + } + + ax88796_data.ax.block_output = xs100_block_output; + ax88796_data.ax.block_input = xs100_block_input; + + pdev = platform_device_register_resndata(&zdev->dev, "ax88796", + zdev->slotaddr, res, 2, + &ax88796_data, + sizeof(ax88796_data)); + + if (IS_ERR(pdev)) { + dev_err(&zdev->dev, "cannot register platform device\n"); + ret = -ENXIO; + goto exit_mem2; + } + + zorro_set_drvdata(zdev, pdev); + + if (!ret) + return 0; + + exit_mem2: + iounmap(ax88796_data.data_area); + + exit_mem: + iounmap(ax88796_data.base_regs); + + exit_req2: + release_mem_region(zdev->resource.start + XS100_8390_DATA32_BASE, + XS100_8390_DATA32_SIZE); + + exit_req: + release_mem_region(zdev->resource.start, 0x100); + + return ret; +} + +static void xsurf100_remove(struct zorro_dev *zdev) +{ + struct platform_device *pdev = zorro_get_drvdata(zdev); + struct xsurf100_ax_plat_data *xs100 = dev_get_platdata(&pdev->dev); + + platform_device_unregister(pdev); + + iounmap(xs100->base_regs); + release_mem_region(zdev->resource.start, 0x100); + iounmap(xs100->data_area); + release_mem_region(zdev->resource.start + XS100_8390_DATA32_BASE, + XS100_8390_DATA32_SIZE); +} + +static const struct zorro_device_id xsurf100_zorro_tbl[] = { + { ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF100, }, + { 0 } +}; + +MODULE_DEVICE_TABLE(zorro, xsurf100_zorro_tbl); + +static struct zorro_driver xsurf100_driver = { + .name = "xsurf100", + .id_table = xsurf100_zorro_tbl, + .probe = xsurf100_probe, + .remove = xsurf100_remove, +}; + +module_driver(xsurf100_driver, zorro_register_driver, zorro_unregister_driver); + +MODULE_DESCRIPTION("X-Surf 100 driver"); +MODULE_AUTHOR("Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de>"); +MODULE_LICENSE("GPL v2"); -- 1.7.0.4
Hi Geert,
On Wed, Apr 18, 2018 at 1:53 AM, Geert Uytterhoeven
<geert@linux-m68k.org> wrote:
>> --- /dev/null
>> +++ b/drivers/net/ethernet/8390/xsurf100.c
>> @@ -0,0 +1,411 @@
>> +#include <linux/module.h>
>> +#include <linux/netdevice.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/zorro.h>
>> +#include <net/ax88796.h>
>> +#include <asm/amigaints.h>
>> +
>> +#define ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF100 \
>> + ZORRO_ID(INDIVIDUAL_COMPUTERS, 0x64, 0)
>
> Another long define to get rid of? ;-)
I decided to leave it that way - it doesn't stick out quite as badly
as the one in the ESP driver. Give me a yell if you insist.
Cheers,
Michael
All,
just noticed belatedly that the Makefile hunk of patch 9 does no
longer apply cleanly in 4.17-rc1, sorry. My series was based on 4.16.
I'll resend that one, OK?
Cheers,
Michael
On Wed, Apr 18, 2018 at 4:26 PM, Michael Schmitz <schmitzmic@gmail.com> wrote:
> This patch series adds support for the Individual Computers X-Surf 100
> network card for m68k Amiga, a network adapter based on the AX88796 chip set.
>
> The driver was originally written for kernel version 3.19 by Michael Karcher
> (see CC:), and adapted to 4.16 for submission to netdev by me. Questions
> regarding motivation for some of the changes are probably best directed at
> Michael Karcher.
>
> The driver has been tested by Adrian <glaubitz@physik.fu-berlin.de> who will
> send his Tested-by tag separately.
>
> A few changes to the ax88796 driver were required:
> - to read the MAC address, some setup of the ax99796 chip must be done,
> - attach to the MII bus only on device open to allow module unloading,
> - allow to supersede ax_block_input/ax_block_output by card-specific
> optimized code,
> - use an optional interrupt status callback to allow easier sharing of the
> card interrupt,
> - set IRQF_SHARED if platform IRQ resource is marked shareable,
>
> The Asix Electronix PHY used on the X-Surf 100 is buggy, and causes the
> software reset to hang if the previous command sent to the PHY was also
> a soft reset. This bug requires addition of a PHY driver for Asix PHYs
> to provide a fixed .soft_reset function, included in this series.
>
> Some additional cleanup:
> - do not attempt to free IRQ in ax_remove (complements 82533ad9a1c),
> - clear platform drvdata on probe fail and module remove.
>
> Changes since v1:
>
> Raised in review by Andrew Lunn:
> - move MII code around to avoid need for forward declaration
> - combine patches 2 and 7 to add cleanup in error path
>
> Changes since v2:
>
> - corrected authorship attribution to Michael Karcher
>
> Suggested by Geert Uytterhoeven:
> - use ei_local->reset_8390() instead of duplicating ax_reset_8390()
> - use %pR to format struct resource pointers
> - assign pdev and xs100 pointers in declaration
> - don't split error messages
> - change Kconfig logic to only require XSURF100 set on Amiga
>
> Suggested by Andrew Lunn:
> - add COMPILE_TEST to ax88796 Kconfig options
> - use new Asix PHY driver for X-Surf 100
>
> Suggested by Andrew Lunn/Finn Thain:
> - declare struct sk_buff in ax88796.h
> - correct whitespace error in ax88796.h
>
> This series' patches, in order:
>
> 1/9 net: phy: new Asix Electronics PHY driver
> 2/9 net: ax88796: Fix MAC address reading
> 3/9 net: ax88796: Attach MII bus only when open
> 4/9 net: ax88796: Do not free IRQ in ax_remove() (already freed in ax_close()).
> 5/9 net: ax88796: Add block_input/output hooks to ax_plat_data
> 6/9 net: ax88796: add interrupt status callback to platform data
> 7/9 net: ax88796: set IRQF_SHARED flag when IRQ resource is marked as shareable
> 8/9 net: ax88796: release platform device drvdata on probe error and module remove
> 9/9 net: New ax88796 platform driver for Amiga X-Surf 100 Zorro board (m68k)
>
> drivers/net/ethernet/8390/Kconfig | 17 ++-
> drivers/net/ethernet/8390/Makefile | 1 +
> drivers/net/ethernet/8390/ax88796.c | 228 ++++++++++++--------
> drivers/net/ethernet/8390/xsurf100.c | 381 ++++++++++++++++++++++++++++++++++
> drivers/net/phy/Kconfig | 6 +
> drivers/net/phy/Makefile | 1 +
> drivers/net/phy/asix.c | 65 ++++++
> drivers/net/phy/phy_device.c | 3 +-
> include/linux/phy.h | 1 +
> include/net/ax88796.h | 14 ++
> 10 files changed, 621 insertions(+), 96 deletions(-)
>
> Cheers,
>
> Michael
On Wed, 18 Apr 2018, Michael Schmitz wrote: > All, > > just noticed belatedly that the Makefile hunk of patch 9 does no > longer apply cleanly in 4.17-rc1, sorry. My series was based on 4.16. > I'll resend that one, OK? > I might end up simpler to resend the whole series -- > Cheers, > > Michael > > > > 1/9 net: phy: new Asix Electronics PHY driver > > 2/9 net: ax88796: Fix MAC address reading > > 3/9 net: ax88796: Attach MII bus only when open > > 4/9 net: ax88796: Do not free IRQ in ax_remove() (already freed in ax_close()). > > 5/9 net: ax88796: Add block_input/output hooks to ax_plat_data I found that git am rejects this one, though 'patch' applies it with fuzz. > > 6/9 net: ax88796: add interrupt status callback to platform data > > 7/9 net: ax88796: set IRQF_SHARED flag when IRQ resource is marked as shareable > > 8/9 net: ax88796: release platform device drvdata on probe error and module remove > > 9/9 net: New ax88796 platform driver for Amiga X-Surf 100 Zorro board (m68k) git am rejected this one and also complained about trailing whitespace. I'd rebase on v4.17-rc1 and also run checkpatch over the results. -- > > > > drivers/net/ethernet/8390/Kconfig | 17 ++- > > drivers/net/ethernet/8390/Makefile | 1 + > > drivers/net/ethernet/8390/ax88796.c | 228 ++++++++++++-------- > > drivers/net/ethernet/8390/xsurf100.c | 381 ++++++++++++++++++++++++++++++++++ > > drivers/net/phy/Kconfig | 6 + > > drivers/net/phy/Makefile | 1 + > > drivers/net/phy/asix.c | 65 ++++++ > > drivers/net/phy/phy_device.c | 3 +- > > include/linux/phy.h | 1 + > > include/net/ax88796.h | 14 ++ > > 10 files changed, 621 insertions(+), 96 deletions(-) > > > > Cheers, > > > > Michael
On 04/18/2018 06:26 AM, Michael Schmitz wrote:
> The Asix Electronics PHY found on the X-Surf 100 Amiga Zorro network
> card by Individual Computers is buggy, and needs the reset bit toggled
> as workaround to make a PHY soft reset succed.
^^^^^^
typo
--
.''`. John Paul Adrian Glaubitz
: :' : Debian Developer - glaubitz@debian.org
`. `' Freie Universitaet Berlin - glaubitz@physik.fu-berlin.de
`- GPG: 62FF 8A75 84E0 2956 9546 0006 7426 3B37 F5B5 F913
Hi Michael, On Wed, Apr 18, 2018 at 12:35 AM, Michael Schmitz <schmitzmic@gmail.com> wrote: > On Wed, Apr 18, 2018 at 1:53 AM, Geert Uytterhoeven > <geert@linux-m68k.org> wrote: >> On Tue, Apr 17, 2018 at 12:04 AM, Michael Schmitz <schmitzmic@gmail.com> wrote: >>> Add platform device driver to populate the ax88796 platform data from >>> information provided by the XSurf100 zorro device driver. >>> This driver will have to be loaded before loading the ax88796 module, >>> or compiled as built-in. >>> --- /dev/null >>> +++ b/drivers/net/ethernet/8390/xsurf100.c >>> +static int xsurf100_probe(struct zorro_dev *zdev, >>> + const struct zorro_device_id *ent) >>> +{ >> >>> + /* error handling for ioremap regs */ >>> + if (!ax88796_data.base_regs) { >>> + dev_err(&zdev->dev, "Cannot ioremap area %p (registers)\n", >>> + (void *)zdev->resource.start); >> >> Please use %pR to format struct resource. >> Documentation/core-api/printk-formats.rst > > The driver uses ioremap to map two subsections of the mem resource for > two different purposes - control register access, and ring buffer > access. The output of %pR may be misleading here (wrong size), and > even more so below. Sorry, I missed it's the same resource. FWIW, if you want to print a phys_addr_t or resource_size_t, you can use %pa, e.g. dev_err(..., "... %pa ...", ... &zdev->resource.start ...); >>> + /* error handling for ioremap data */ >>> + if (!ax88796_data.data_area) { >>> + dev_err(&zdev->dev, "Cannot ioremap area %p (32-bit access)\n", >>> + (void *)zdev->resource.start + XS100_8390_DATA32_BASE); >> >> %pR > > I've added the offset into the mem resource here to clarify what we've > tried to map. That's an alternative solution, fine for me. Gr{oetje,eeting}s, Geert -- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds
> +
> +/**
> + * asix_soft_reset - software reset the PHY via BMCR_RESET bit
> + * @phydev: target phy_device struct
> + *
> + * Description: Perform a software PHY reset using the standard
> + * BMCR_RESET bit and poll for the reset bit to be cleared.
> + * Toggle BMCR_RESET bit off to accomodate broken PHY implementations
> + * such as used on the Individual Computers' X-Surf 100 Zorro card.
> + *
> + * Returns: 0 on success, < 0 on failure
> + */
> +static int asix_soft_reset(struct phy_device *phydev)
> +{
> + int ret;
> +
> + /* Asix PHY won't reset unless reset bit toggles */
> + ret = phy_write(phydev, MII_BMCR, 0);
> + if (ret < 0)
> + return ret;
> +
> + phy_write(phydev, MII_BMCR, BMCR_RESET);
> +
> + return phy_poll_reset(phydev);
> +}
Why not simply:
static int asix_soft_reset(struct phy_device *phydev)
{
int ret;
/* Asix PHY won't reset unless reset bit toggles */
ret = phy_write(phydev, MII_BMCR, 0);
if (ret < 0)
return ret;
return genphy_soft_reset(phydev);
}
Andrew
On Wed, Apr 18, 2018 at 05:10:45PM +1200, Michael Schmitz wrote:
> All,
>
> just noticed belatedly that the Makefile hunk of patch 9 does no
> longer apply cleanly in 4.17-rc1, sorry. My series was based on 4.16.
> I'll resend that one, OK?
Hi Michael
You should be based on DaveM net-next tree:
git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git
Please also have "net-next" in the patch subject. See
Documentation/networking/netdev-FAQ.txt
Andrew
Hi Finn, thanks for the feedback! On Wed, Apr 18, 2018 at 5:45 PM, Finn Thain <fthain@telegraphics.com.au> wrote: >> > 1/9 net: phy: new Asix Electronics PHY driver >> > 2/9 net: ax88796: Fix MAC address reading >> > 3/9 net: ax88796: Attach MII bus only when open >> > 4/9 net: ax88796: Do not free IRQ in ax_remove() (already freed in ax_close()). >> > 5/9 net: ax88796: Add block_input/output hooks to ax_plat_data > > I found that git am rejects this one, though 'patch' applies it with fuzz. Can't remember seeing anything there when rebasing the series, odd. > >> > 6/9 net: ax88796: add interrupt status callback to platform data >> > 7/9 net: ax88796: set IRQF_SHARED flag when IRQ resource is marked as shareable >> > 8/9 net: ax88796: release platform device drvdata on probe error and module remove >> > 9/9 net: New ax88796 platform driver for Amiga X-Surf 100 Zorro board (m68k) > > git am rejected this one and also complained about trailing whitespace. > > I'd rebase on v4.17-rc1 and also run checkpatch over the results. Done that now, thanks. Andrew recommended basing my patches on net-next so I'll do that before resubmitting. Cheers, Michael > -- > >> > >> > drivers/net/ethernet/8390/Kconfig | 17 ++- >> > drivers/net/ethernet/8390/Makefile | 1 + >> > drivers/net/ethernet/8390/ax88796.c | 228 ++++++++++++-------- >> > drivers/net/ethernet/8390/xsurf100.c | 381 ++++++++++++++++++++++++++++++++++ >> > drivers/net/phy/Kconfig | 6 + >> > drivers/net/phy/Makefile | 1 + >> > drivers/net/phy/asix.c | 65 ++++++ >> > drivers/net/phy/phy_device.c | 3 +- >> > include/linux/phy.h | 1 + >> > include/net/ax88796.h | 14 ++ >> > 10 files changed, 621 insertions(+), 96 deletions(-) >> > >> > Cheers, >> > >> > Michael
Hi Andrew,
sorry, my mistake. I didn't realize how fast DaveM's tree diverges
from Linus' (and Geert's) once the merge window opens.
Cheers,
Michael
On Thu, Apr 19, 2018 at 12:19 AM, Andrew Lunn <andrew@lunn.ch> wrote:
> On Wed, Apr 18, 2018 at 05:10:45PM +1200, Michael Schmitz wrote:
>> All,
>>
>> just noticed belatedly that the Makefile hunk of patch 9 does no
>> longer apply cleanly in 4.17-rc1, sorry. My series was based on 4.16.
>> I'll resend that one, OK?
>
> Hi Michael
>
> You should be based on DaveM net-next tree:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git
>
> Please also have "net-next" in the patch subject. See
> Documentation/networking/netdev-FAQ.txt
>
> Andrew
Hi Andrew,
I agree, that's much better. I had something like that in mind before
I got distracted...
/me looking for brown paper bag now.
Cheers,
Michael
On Thu, Apr 19, 2018 at 12:13 AM, Andrew Lunn <andrew@lunn.ch> wrote:
>> +
>> +/**
>> + * asix_soft_reset - software reset the PHY via BMCR_RESET bit
>> + * @phydev: target phy_device struct
>> + *
>> + * Description: Perform a software PHY reset using the standard
>> + * BMCR_RESET bit and poll for the reset bit to be cleared.
>> + * Toggle BMCR_RESET bit off to accomodate broken PHY implementations
>> + * such as used on the Individual Computers' X-Surf 100 Zorro card.
>> + *
>> + * Returns: 0 on success, < 0 on failure
>> + */
>> +static int asix_soft_reset(struct phy_device *phydev)
>> +{
>> + int ret;
>> +
>> + /* Asix PHY won't reset unless reset bit toggles */
>> + ret = phy_write(phydev, MII_BMCR, 0);
>> + if (ret < 0)
>> + return ret;
>> +
>> + phy_write(phydev, MII_BMCR, BMCR_RESET);
>> +
>> + return phy_poll_reset(phydev);
>> +}
>
> Why not simply:
>
> static int asix_soft_reset(struct phy_device *phydev)
> {
> int ret;
>
> /* Asix PHY won't reset unless reset bit toggles */
> ret = phy_write(phydev, MII_BMCR, 0);
> if (ret < 0)
> return ret;
>
> return genphy_soft_reset(phydev);
> }
>
> Andrew
> --
> To unsubscribe from this list: send the line "unsubscribe linux-m68k" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
[This is a resend of my v3 series which was based on the wrong version and tree. Only substantial change is to Asix AX99796B PHY driver.] This patch series adds support for the Individual Computers X-Surf 100 network card for m68k Amiga, a network adapter based on the AX88796 chip set. The driver was originally written for kernel version 3.19 by Michael Karcher (see CC:), and adapted to 4.16+ for submission to netdev by me. Questions regarding motivation for some of the changes are probably best directed at Michael Karcher. The driver has been tested by Adrian <glaubitz@physik.fu-berlin.de> who will send his Tested-by tag separately. A few changes to the ax88796 driver were required: - to read the MAC address, some setup of the ax99796 chip must be done, - attach to the MII bus only on device open to allow module unloading, - allow to supersede ax_block_input/ax_block_output by card-specific optimized code, - use an optional interrupt status callback to allow easier sharing of the card interrupt, - set IRQF_SHARED if platform IRQ resource is marked shareable The Asix Electronix PHY used on the X-Surf 100 is buggy, and causes the software reset to hang if the previous command sent to the PHY was also a soft reset. This bug requires addition of a PHY driver for Asix PHYs to provide a fixed .soft_reset function, included in this series. Some additional cleanup: - do not attempt to free IRQ in ax_remove (complements 82533ad9a1c), - clear platform drvdata on probe fail and module remove. Changes since v1: Raised in review by Andrew Lunn: - move MII code around to avoid need for forward declaration, - combine patches 2 and 7 to add cleanup in error path Changes since v2: - corrected authorship attribution to Michael Karcher Suggested by Geert Uytterhoeven: - use ei_local->reset_8390() instead of duplicating ax_reset_8390(), - use %pR to format struct resource pointers, - assign pdev and xs100 pointers in declaration, - don't split error messages, - change Kconfig logic to only require XSURF100 set on Amiga Suggested by Andrew Lunn: - add COMPILE_TEST to ax88796 Kconfig options, - use new Asix PHY driver for X-Surf 100 Suggested by Andrew Lunn/Finn Thain: - declare struct sk_buff in ax88796.h, - correct whitespace error in ax88796.h Changes since v3: - various checkpatch cleanup Andrew Lunn: - don't duplicate genphy_soft_reset in Asix PHY driver, just call genphy_soft_reset after writing zero to control register This series' patches, in order: 1/9 net-next: phy: new Asix Electronics PHY driver 2/9 net-next: ax88796: Fix MAC address reading 3/9 net-next: ax88796: Attach MII bus only when open 4/9 net-next: ax88796: Do not free IRQ in ax_remove() (already freed in ax_close()). 5/9 net-next: ax88796: Add block_input/output hooks to ax_plat_data 6/9 net-next: ax88796: add interrupt status callback to platform data 7/9 net-next: ax88796: set IRQF_SHARED flag when IRQ resource is marked as shareable 8/9 net-next: ax88796: release platform device drvdata on probe error and module remove 9/9 net-next: New ax88796 platform driver for Amiga X-Surf 100 Zorro board (m68k) drivers/net/ethernet/8390/Kconfig | 17 ++- drivers/net/ethernet/8390/Makefile | 1 + drivers/net/ethernet/8390/ax88796.c | 228 ++++++++++++-------- drivers/net/ethernet/8390/xsurf100.c | 382 ++++++++++++++++++++++++++++++++++ drivers/net/phy/Kconfig | 6 + drivers/net/phy/Makefile | 1 + drivers/net/phy/asix.c | 63 ++++++ include/net/ax88796.h | 14 ++ 8 files changed, 617 insertions(+), 95 deletions(-) Cheers, Michael
The Asix Electronics PHY found on the X-Surf 100 Amiga Zorro network card by Individual Computers is buggy, and needs the reset bit toggled as workaround to make a PHY soft reset succeed. Add workaround driver just for this special case. Suggested in xsurf100 patch series review by Andrew Lunn <andrew@lunn.ch> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> --- Changes in v4: Andrew Lunn: - don't duplicate genphy_soft_reset, just call after writing zero to control register --- drivers/net/phy/Kconfig | 6 ++++ drivers/net/phy/Makefile | 1 + drivers/net/phy/asix.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 0 deletions(-) create mode 100644 drivers/net/phy/asix.c diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index bdfbabb..edb8b9a 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -218,6 +218,12 @@ config AQUANTIA_PHY ---help--- Currently supports the Aquantia AQ1202, AQ2104, AQR105, AQR405 +config ASIX_PHY + tristate "Asix PHYs" + help + Currently supports the Asix Electronics PHY found in the X-Surf 100 + AX88796B package. + config AT803X_PHY tristate "AT803X PHYs" ---help--- diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 01acbcb..701ca0b 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -45,6 +45,7 @@ obj-y += $(sfp-obj-y) $(sfp-obj-m) obj-$(CONFIG_AMD_PHY) += amd.o obj-$(CONFIG_AQUANTIA_PHY) += aquantia.o +obj-$(CONFIG_ASIX_PHY) += asix.o obj-$(CONFIG_AT803X_PHY) += at803x.o obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o obj-$(CONFIG_BCM7XXX_PHY) += bcm7xxx.o diff --git a/drivers/net/phy/asix.c b/drivers/net/phy/asix.c new file mode 100644 index 0000000..8ebe7f5 --- /dev/null +++ b/drivers/net/phy/asix.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Driver for Asix PHYs + * + * Author: Michael Schmitz <schmitzmic@gmail.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/mii.h> +#include <linux/phy.h> + +#define PHY_ID_ASIX_AX88796B 0x003b1841 + +MODULE_DESCRIPTION("Asix PHY driver"); +MODULE_AUTHOR("Michael Schmitz <schmitzmic@gmail.com>"); +MODULE_LICENSE("GPL"); + +/** + * asix_soft_reset - software reset the PHY via BMCR_RESET bit + * @phydev: target phy_device struct + * + * Description: Perform a software PHY reset using the standard + * BMCR_RESET bit and poll for the reset bit to be cleared. + * Toggle BMCR_RESET bit off to accommodate broken AX8796B PHY implementation + * such as used on the Individual Computers' X-Surf 100 Zorro card. + * + * Returns: 0 on success, < 0 on failure + */ +static int asix_soft_reset(struct phy_device *phydev) +{ + int ret; + + /* Asix PHY won't reset unless reset bit toggles */ + ret = phy_write(phydev, MII_BMCR, 0); + if (ret < 0) + return ret; + + return genphy_soft_reset(phydev); +} + +static struct phy_driver asix_driver[] = { { + .phy_id = PHY_ID_ASIX_AX88796B, + .name = "Asix Electronics AX88796B", + .phy_id_mask = 0xfffffff0, + .features = PHY_BASIC_FEATURES, + .soft_reset = asix_soft_reset, +} }; + +module_phy_driver(asix_driver); + +static struct mdio_device_id __maybe_unused asix_tbl[] = { + { PHY_ID_ASIX_AX88796B, 0xfffffff0 }, + { } +}; + +MODULE_DEVICE_TABLE(mdio, asix_tbl); -- 1.7.0.4
From: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> To read the MAC address from the (virtual) SAprom, the remote DMA unit needs to be set up like for every other process access to card-local memory. Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> --- drivers/net/ethernet/8390/ax88796.c | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-) diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index da61cf3..ae39375 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -669,10 +669,16 @@ static int ax_init_dev(struct net_device *dev) if (ax->plat->flags & AXFLG_HAS_EEPROM) { unsigned char SA_prom[32]; + ei_outb(6, ioaddr + EN0_RCNTLO); + ei_outb(0, ioaddr + EN0_RCNTHI); + ei_outb(0, ioaddr + EN0_RSARLO); + ei_outb(0, ioaddr + EN0_RSARHI); + ei_outb(E8390_RREAD + E8390_START, ioaddr + NE_CMD); for (i = 0; i < sizeof(SA_prom); i += 2) { SA_prom[i] = ei_inb(ioaddr + NE_DATAPORT); SA_prom[i + 1] = ei_inb(ioaddr + NE_DATAPORT); } + ei_outb(ENISR_RDC, ioaddr + EN0_ISR); /* Ack intr. */ if (ax->plat->wordlength == 2) for (i = 0; i < 16; i++) -- 1.7.0.4
From: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Call ax_mii_init in ax_open(), and unregister/remove mdiobus resources in ax_close(). This is needed to be able to unload the module, as the module is busy while the MII bus is attached. Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> Reviewed-by: Andrew Lunn <andrew@lunn.ch> --- drivers/net/ethernet/8390/ax88796.c | 183 ++++++++++++++++++----------------- 1 files changed, 95 insertions(+), 88 deletions(-) diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index ae39375..ab020e6 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -387,6 +387,90 @@ static void ax_phy_switch(struct net_device *dev, int on) ei_outb(reg_gpoc, ei_local->mem + EI_SHIFT(0x17)); } +static void ax_bb_mdc(struct mdiobb_ctrl *ctrl, int level) +{ + struct ax_device *ax = container_of(ctrl, struct ax_device, bb_ctrl); + + if (level) + ax->reg_memr |= AX_MEMR_MDC; + else + ax->reg_memr &= ~AX_MEMR_MDC; + + ei_outb(ax->reg_memr, ax->addr_memr); +} + +static void ax_bb_dir(struct mdiobb_ctrl *ctrl, int output) +{ + struct ax_device *ax = container_of(ctrl, struct ax_device, bb_ctrl); + + if (output) + ax->reg_memr &= ~AX_MEMR_MDIR; + else + ax->reg_memr |= AX_MEMR_MDIR; + + ei_outb(ax->reg_memr, ax->addr_memr); +} + +static void ax_bb_set_data(struct mdiobb_ctrl *ctrl, int value) +{ + struct ax_device *ax = container_of(ctrl, struct ax_device, bb_ctrl); + + if (value) + ax->reg_memr |= AX_MEMR_MDO; + else + ax->reg_memr &= ~AX_MEMR_MDO; + + ei_outb(ax->reg_memr, ax->addr_memr); +} + +static int ax_bb_get_data(struct mdiobb_ctrl *ctrl) +{ + struct ax_device *ax = container_of(ctrl, struct ax_device, bb_ctrl); + int reg_memr = ei_inb(ax->addr_memr); + + return reg_memr & AX_MEMR_MDI ? 1 : 0; +} + +static const struct mdiobb_ops bb_ops = { + .owner = THIS_MODULE, + .set_mdc = ax_bb_mdc, + .set_mdio_dir = ax_bb_dir, + .set_mdio_data = ax_bb_set_data, + .get_mdio_data = ax_bb_get_data, +}; + +static int ax_mii_init(struct net_device *dev) +{ + struct platform_device *pdev = to_platform_device(dev->dev.parent); + struct ei_device *ei_local = netdev_priv(dev); + struct ax_device *ax = to_ax_dev(dev); + int err; + + ax->bb_ctrl.ops = &bb_ops; + ax->addr_memr = ei_local->mem + AX_MEMR; + ax->mii_bus = alloc_mdio_bitbang(&ax->bb_ctrl); + if (!ax->mii_bus) { + err = -ENOMEM; + goto out; + } + + ax->mii_bus->name = "ax88796_mii_bus"; + ax->mii_bus->parent = dev->dev.parent; + snprintf(ax->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", + pdev->name, pdev->id); + + err = mdiobus_register(ax->mii_bus); + if (err) + goto out_free_mdio_bitbang; + + return 0; + + out_free_mdio_bitbang: + free_mdio_bitbang(ax->mii_bus); + out: + return err; +} + static int ax_open(struct net_device *dev) { struct ax_device *ax = to_ax_dev(dev); @@ -394,6 +478,10 @@ static int ax_open(struct net_device *dev) netdev_dbg(dev, "open\n"); + ret = ax_mii_init(dev); + if (ret) + goto failed_mii; + ret = request_irq(dev->irq, ax_ei_interrupt, ax->irqflags, dev->name, dev); if (ret) @@ -421,6 +509,10 @@ static int ax_open(struct net_device *dev) ax_phy_switch(dev, 0); free_irq(dev->irq, dev); failed_request_irq: + /* unregister mdiobus */ + mdiobus_unregister(ax->mii_bus); + free_mdio_bitbang(ax->mii_bus); + failed_mii: return ret; } @@ -440,6 +532,9 @@ static int ax_close(struct net_device *dev) phy_disconnect(dev->phydev); free_irq(dev->irq, dev); + + mdiobus_unregister(ax->mii_bus); + free_mdio_bitbang(ax->mii_bus); return 0; } @@ -539,92 +634,8 @@ static void ax_eeprom_register_write(struct eeprom_93cx6 *eeprom) #endif }; -static void ax_bb_mdc(struct mdiobb_ctrl *ctrl, int level) -{ - struct ax_device *ax = container_of(ctrl, struct ax_device, bb_ctrl); - - if (level) - ax->reg_memr |= AX_MEMR_MDC; - else - ax->reg_memr &= ~AX_MEMR_MDC; - - ei_outb(ax->reg_memr, ax->addr_memr); -} - -static void ax_bb_dir(struct mdiobb_ctrl *ctrl, int output) -{ - struct ax_device *ax = container_of(ctrl, struct ax_device, bb_ctrl); - - if (output) - ax->reg_memr &= ~AX_MEMR_MDIR; - else - ax->reg_memr |= AX_MEMR_MDIR; - - ei_outb(ax->reg_memr, ax->addr_memr); -} - -static void ax_bb_set_data(struct mdiobb_ctrl *ctrl, int value) -{ - struct ax_device *ax = container_of(ctrl, struct ax_device, bb_ctrl); - - if (value) - ax->reg_memr |= AX_MEMR_MDO; - else - ax->reg_memr &= ~AX_MEMR_MDO; - - ei_outb(ax->reg_memr, ax->addr_memr); -} - -static int ax_bb_get_data(struct mdiobb_ctrl *ctrl) -{ - struct ax_device *ax = container_of(ctrl, struct ax_device, bb_ctrl); - int reg_memr = ei_inb(ax->addr_memr); - - return reg_memr & AX_MEMR_MDI ? 1 : 0; -} - -static const struct mdiobb_ops bb_ops = { - .owner = THIS_MODULE, - .set_mdc = ax_bb_mdc, - .set_mdio_dir = ax_bb_dir, - .set_mdio_data = ax_bb_set_data, - .get_mdio_data = ax_bb_get_data, -}; - /* setup code */ -static int ax_mii_init(struct net_device *dev) -{ - struct platform_device *pdev = to_platform_device(dev->dev.parent); - struct ei_device *ei_local = netdev_priv(dev); - struct ax_device *ax = to_ax_dev(dev); - int err; - - ax->bb_ctrl.ops = &bb_ops; - ax->addr_memr = ei_local->mem + AX_MEMR; - ax->mii_bus = alloc_mdio_bitbang(&ax->bb_ctrl); - if (!ax->mii_bus) { - err = -ENOMEM; - goto out; - } - - ax->mii_bus->name = "ax88796_mii_bus"; - ax->mii_bus->parent = dev->dev.parent; - snprintf(ax->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", - pdev->name, pdev->id); - - err = mdiobus_register(ax->mii_bus); - if (err) - goto out_free_mdio_bitbang; - - return 0; - - out_free_mdio_bitbang: - free_mdio_bitbang(ax->mii_bus); - out: - return err; -} - static void ax_initial_setup(struct net_device *dev, struct ei_device *ei_local) { void __iomem *ioaddr = ei_local->mem; @@ -755,10 +766,6 @@ static int ax_init_dev(struct net_device *dev) dev->netdev_ops = &ax_netdev_ops; dev->ethtool_ops = &ax_ethtool_ops; - ret = ax_mii_init(dev); - if (ret) - goto err_out; - ax_NS8390_init(dev, 0); ret = register_netdev(dev); -- 1.7.0.4
From: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> This complements the fix in 82533ad9a1c ("net: ethernet: ax88796: don't call free_irq without request_irq first") that removed the free_irq call in the error path of probe, to also not call free_irq when remove is called to revert the effects of probe. Fixes: 82533ad9a1c (net: ethernet: ax88796: don't call free_irq without request_irq first) Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> Reviewed-by: Geert Uytterhoeven <geert@linux-m68k.org> --- drivers/net/ethernet/8390/ax88796.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index ab020e6..d3f30f1 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -790,7 +790,6 @@ static int ax_remove(struct platform_device *pdev) struct resource *mem; unregister_netdev(dev); - free_irq(dev->irq, dev); iounmap(ei_local->mem); mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- 1.7.0.4
From: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Add platform specific hooks for block transfer reads/writes of packet buffer data, superseding the default provided ax_block_input/output. Currently used for m68k Amiga XSurf100. Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> --- Changes in v3: Suggested by Andrew Lunn/Finn Thain: - declare struct sk_buff in ax88796.h - correct whitespace error in ax88796.h --- drivers/net/ethernet/8390/ax88796.c | 10 ++++++++-- include/net/ax88796.h | 9 +++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index d3f30f1..939a572 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -758,8 +758,14 @@ static int ax_init_dev(struct net_device *dev) #endif ei_local->reset_8390 = &ax_reset_8390; - ei_local->block_input = &ax_block_input; - ei_local->block_output = &ax_block_output; + if (ax->plat->block_input) + ei_local->block_input = ax->plat->block_input; + else + ei_local->block_input = &ax_block_input; + if (ax->plat->block_output) + ei_local->block_output = ax->plat->block_output; + else + ei_local->block_output = &ax_block_output; ei_local->get_8390_hdr = &ax_get_8390_hdr; ei_local->priv = 0; diff --git a/include/net/ax88796.h b/include/net/ax88796.h index b9a3bec..363b0ca 100644 --- a/include/net/ax88796.h +++ b/include/net/ax88796.h @@ -12,6 +12,9 @@ #ifndef __NET_AX88796_PLAT_H #define __NET_AX88796_PLAT_H +struct sk_buff; +struct net_device; + #define AXFLG_HAS_EEPROM (1<<0) #define AXFLG_MAC_FROMDEV (1<<1) /* device already has MAC */ #define AXFLG_HAS_93CX6 (1<<2) /* use eeprom_93cx6 driver */ @@ -26,6 +29,12 @@ struct ax_plat_data { u32 *reg_offsets; /* register offsets */ u8 *mac_addr; /* MAC addr (only used when AXFLG_MAC_FROMPLATFORM is used */ + + /* uses default ax88796 buffer if set to NULL */ + void (*block_output)(struct net_device *dev, int count, + const unsigned char *buf, int star_page); + void (*block_input)(struct net_device *dev, int count, + struct sk_buff *skb, int ring_offset); }; #endif /* __NET_AX88796_PLAT_H */ -- 1.7.0.4
From: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> To be able to tell the ax88796 driver whether it is sensible to enter the 8390 interrupt handler, an "is this interrupt caused by the 88796" callback has been added to the ax_plat_data structure (with NULL being compatible to the previous behaviour). Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> --- drivers/net/ethernet/8390/ax88796.c | 23 +++++++++++++++++++++-- include/net/ax88796.h | 5 +++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index 939a572..d283ed0 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -163,6 +163,21 @@ static void ax_reset_8390(struct net_device *dev) ei_outb(ENISR_RESET, addr + EN0_ISR); /* Ack intr. */ } +/* Wrapper for __ei_interrupt for platforms that have a platform-specific + * way to find out whether the interrupt request might be caused by + * the ax88796 chip. + */ +static irqreturn_t ax_ei_interrupt_filtered(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct ax_device *ax = to_ax_dev(dev); + struct platform_device *pdev = to_platform_device(dev->dev.parent); + + if (!ax->plat->check_irq(pdev)) + return IRQ_NONE; + + return ax_ei_interrupt(irq, dev_id); +} static void ax_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page) @@ -482,8 +497,12 @@ static int ax_open(struct net_device *dev) if (ret) goto failed_mii; - ret = request_irq(dev->irq, ax_ei_interrupt, ax->irqflags, - dev->name, dev); + if (ax->plat->check_irq) + ret = request_irq(dev->irq, ax_ei_interrupt_filtered, + ax->irqflags, dev->name, dev); + else + ret = request_irq(dev->irq, ax_ei_interrupt, ax->irqflags, + dev->name, dev); if (ret) goto failed_request_irq; diff --git a/include/net/ax88796.h b/include/net/ax88796.h index 363b0ca..84b3785 100644 --- a/include/net/ax88796.h +++ b/include/net/ax88796.h @@ -14,6 +14,7 @@ struct sk_buff; struct net_device; +struct platform_device; #define AXFLG_HAS_EEPROM (1<<0) #define AXFLG_MAC_FROMDEV (1<<1) /* device already has MAC */ @@ -35,6 +36,10 @@ struct ax_plat_data { const unsigned char *buf, int star_page); void (*block_input)(struct net_device *dev, int count, struct sk_buff *skb, int ring_offset); + /* returns nonzero if a pending interrupt request might by caused by + * the ax88786. Handles all interrupts if set to NULL + */ + int (*check_irq)(struct platform_device *pdev); }; #endif /* __NET_AX88796_PLAT_H */ -- 1.7.0.4
From: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> On the Amiga X-Surf100, the network card interrupt is shared with many other interrupt sources, so requires the IRQF_SHARED flag to register. Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> --- drivers/net/ethernet/8390/ax88796.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index d283ed0..229279f 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -872,6 +872,9 @@ static int ax_probe(struct platform_device *pdev) dev->irq = irq->start; ax->irqflags = irq->flags & IRQF_TRIGGER_MASK; + if (irq->flags & IORESOURCE_IRQ_SHAREABLE) + ax->irqflags |= IRQF_SHARED; + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!mem) { dev_err(&pdev->dev, "no MEM specified\n"); -- 1.7.0.4
The net device struct pointer is stored as platform device drvdata on module probe - clear the drvdata entry on probe fail there, as well as when unloading the module. Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> --- drivers/net/ethernet/8390/ax88796.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index 229279f..2a0ddec 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -826,6 +826,7 @@ static int ax_remove(struct platform_device *pdev) release_mem_region(mem->start, resource_size(mem)); } + platform_set_drvdata(pdev, NULL); free_netdev(dev); return 0; @@ -959,6 +960,7 @@ static int ax_probe(struct platform_device *pdev) release_mem_region(mem->start, mem_size); exit_mem: + platform_set_drvdata(pdev, NULL); free_netdev(dev); return ret; -- 1.7.0.4
From: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Add platform device driver to populate the ax88796 platform data from information provided by the XSurf100 zorro device driver. The ax88796 module will be loaded through this module's probe function. Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> --- Changes in v3: Suggested by Geert Uytterhoeven: - use ei_local->reset_8390() instead of duplicating ax_reset_8390() - use %pR to format struct resource pointers - assign pdev and xs100 pointers in declaration - don't split error messages - change Kconfig logic to only require XSURF100 set on Amiga Suggested by Andrew Lunn: - add COMPILE_TEST to ax88796 Kconfig options - use new Asix PHY driver for X-Surf 100 --- drivers/net/ethernet/8390/Kconfig | 17 ++- drivers/net/ethernet/8390/Makefile | 1 + drivers/net/ethernet/8390/xsurf100.c | 382 ++++++++++++++++++++++++++++++++++ 3 files changed, 398 insertions(+), 2 deletions(-) create mode 100644 drivers/net/ethernet/8390/xsurf100.c diff --git a/drivers/net/ethernet/8390/Kconfig b/drivers/net/ethernet/8390/Kconfig index 9fee7c8..f2f0264 100644 --- a/drivers/net/ethernet/8390/Kconfig +++ b/drivers/net/ethernet/8390/Kconfig @@ -29,8 +29,8 @@ config PCMCIA_AXNET called axnet_cs. If unsure, say N. config AX88796 - tristate "ASIX AX88796 NE2000 clone support" - depends on (ARM || MIPS || SUPERH) + tristate "ASIX AX88796 NE2000 clone support" if !ZORRO + depends on (ARM || MIPS || SUPERH || ZORRO || COMPILE_TEST) select CRC32 select PHYLIB select MDIO_BITBANG @@ -45,6 +45,19 @@ config AX88796_93CX6 ---help--- Select this if your platform comes with an external 93CX6 eeprom. +config XSURF100 + tristate "Amiga XSurf 100 AX88796/NE2000 clone support" + depends on ZORRO + select AX88796 + select ASIX_PHY + help + This driver is for the Individual Computers X-Surf 100 Ethernet + card (based on the Asix AX88796 chip). If you have such a card, + say Y. Otherwise, say N. + + To compile this driver as a module, choose M here: the module + will be called xsurf100. + config HYDRA tristate "Hydra support" depends on ZORRO diff --git a/drivers/net/ethernet/8390/Makefile b/drivers/net/ethernet/8390/Makefile index 1d650e6..85c83c5 100644 --- a/drivers/net/ethernet/8390/Makefile +++ b/drivers/net/ethernet/8390/Makefile @@ -16,4 +16,5 @@ obj-$(CONFIG_PCMCIA_PCNET) += pcnet_cs.o 8390.o obj-$(CONFIG_STNIC) += stnic.o 8390.o obj-$(CONFIG_ULTRA) += smc-ultra.o 8390.o obj-$(CONFIG_WD80x3) += wd.o 8390.o +obj-$(CONFIG_XSURF100) += xsurf100.o obj-$(CONFIG_ZORRO8390) += zorro8390.o diff --git a/drivers/net/ethernet/8390/xsurf100.c b/drivers/net/ethernet/8390/xsurf100.c new file mode 100644 index 0000000..e2c9638 --- /dev/null +++ b/drivers/net/ethernet/8390/xsurf100.c @@ -0,0 +1,382 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/platform_device.h> +#include <linux/zorro.h> +#include <net/ax88796.h> +#include <asm/amigaints.h> + +#define ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF100 \ + ZORRO_ID(INDIVIDUAL_COMPUTERS, 0x64, 0) + +#define XS100_IRQSTATUS_BASE 0x40 +#define XS100_8390_BASE 0x800 + +/* Longword-access area. Translated to 2 16-bit access cycles by the + * X-Surf 100 FPGA + */ +#define XS100_8390_DATA32_BASE 0x8000 +#define XS100_8390_DATA32_SIZE 0x2000 +/* Sub-Areas for fast data register access; addresses relative to area begin */ +#define XS100_8390_DATA_READ32_BASE 0x0880 +#define XS100_8390_DATA_WRITE32_BASE 0x0C80 +#define XS100_8390_DATA_AREA_SIZE 0x80 + +#define __NS8390_init ax_NS8390_init + +/* force unsigned long back to 'void __iomem *' */ +#define ax_convert_addr(_a) ((void __force __iomem *)(_a)) + +#define ei_inb(_a) z_readb(ax_convert_addr(_a)) +#define ei_outb(_v, _a) z_writeb(_v, ax_convert_addr(_a)) + +#define ei_inw(_a) z_readw(ax_convert_addr(_a)) +#define ei_outw(_v, _a) z_writew(_v, ax_convert_addr(_a)) + +#define ei_inb_p(_a) ei_inb(_a) +#define ei_outb_p(_v, _a) ei_outb(_v, _a) + +/* define EI_SHIFT() to take into account our register offsets */ +#define EI_SHIFT(x) (ei_local->reg_offset[(x)]) + +/* Ensure we have our RCR base value */ +#define AX88796_PLATFORM + +static unsigned char version[] = + "ax88796.c: Copyright 2005,2007 Simtec Electronics\n"; + +#include "lib8390.c" + +/* from ne.c */ +#define NE_CMD EI_SHIFT(0x00) +#define NE_RESET EI_SHIFT(0x1f) +#define NE_DATAPORT EI_SHIFT(0x10) + +struct xsurf100_ax_plat_data { + struct ax_plat_data ax; + void __iomem *base_regs; + void __iomem *data_area; +}; + +static int is_xsurf100_network_irq(struct platform_device *pdev) +{ + struct xsurf100_ax_plat_data *xs100 = dev_get_platdata(&pdev->dev); + + return (readw(xs100->base_regs + XS100_IRQSTATUS_BASE) & 0xaaaa) != 0; +} + +/* These functions guarantee that the iomem is accessed with 32 bit + * cycles only. z_memcpy_fromio / z_memcpy_toio don't + */ +static void z_memcpy_fromio32(void *dst, const void __iomem *src, size_t bytes) +{ + while (bytes > 32) { + asm __volatile__ + ("movem.l (%0)+,%%d0-%%d7\n" + "movem.l %%d0-%%d7,(%1)\n" + "adda.l #32,%1" : "=a"(src), "=a"(dst) + : "0"(src), "1"(dst) : "d0", "d1", "d2", "d3", "d4", + "d5", "d6", "d7", "memory"); + bytes -= 32; + } + while (bytes) { + *(uint32_t *)dst = z_readl(src); + src += 4; + dst += 4; + bytes -= 4; + } +} + +static void z_memcpy_toio32(void __iomem *dst, const void *src, size_t bytes) +{ + while (bytes) { + z_writel(*(const uint32_t *)src, dst); + src += 4; + dst += 4; + bytes -= 4; + } +} + +static void xs100_write(struct net_device *dev, const void *src, + unsigned int count) +{ + struct ei_device *ei_local = netdev_priv(dev); + struct platform_device *pdev = to_platform_device(dev->dev.parent); + struct xsurf100_ax_plat_data *xs100 = dev_get_platdata(&pdev->dev); + + /* copy whole blocks */ + while (count > XS100_8390_DATA_AREA_SIZE) { + z_memcpy_toio32(xs100->data_area + + XS100_8390_DATA_WRITE32_BASE, src, + XS100_8390_DATA_AREA_SIZE); + src += XS100_8390_DATA_AREA_SIZE; + count -= XS100_8390_DATA_AREA_SIZE; + } + /* copy whole dwords */ + z_memcpy_toio32(xs100->data_area + XS100_8390_DATA_WRITE32_BASE, + src, count & ~3); + src += count & ~3; + if (count & 2) { + ei_outw(*(uint16_t *)src, ei_local->mem + NE_DATAPORT); + src += 2; + } + if (count & 1) + ei_outb(*(uint8_t *)src, ei_local->mem + NE_DATAPORT); +} + +static void xs100_read(struct net_device *dev, void *dst, unsigned int count) +{ + struct ei_device *ei_local = netdev_priv(dev); + struct platform_device *pdev = to_platform_device(dev->dev.parent); + struct xsurf100_ax_plat_data *xs100 = dev_get_platdata(&pdev->dev); + + /* copy whole blocks */ + while (count > XS100_8390_DATA_AREA_SIZE) { + z_memcpy_fromio32(dst, xs100->data_area + + XS100_8390_DATA_READ32_BASE, + XS100_8390_DATA_AREA_SIZE); + dst += XS100_8390_DATA_AREA_SIZE; + count -= XS100_8390_DATA_AREA_SIZE; + } + /* copy whole dwords */ + z_memcpy_fromio32(dst, xs100->data_area + XS100_8390_DATA_READ32_BASE, + count & ~3); + dst += count & ~3; + if (count & 2) { + *(uint16_t *)dst = ei_inw(ei_local->mem + NE_DATAPORT); + dst += 2; + } + if (count & 1) + *(uint8_t *)dst = ei_inb(ei_local->mem + NE_DATAPORT); +} + +/* Block input and output, similar to the Crynwr packet driver. If + * you are porting to a new ethercard, look at the packet driver + * source for hints. The NEx000 doesn't share the on-board packet + * memory -- you have to put the packet out through the "remote DMA" + * dataport using ei_outb. + */ +static void xs100_block_input(struct net_device *dev, int count, + struct sk_buff *skb, int ring_offset) +{ + struct ei_device *ei_local = netdev_priv(dev); + void __iomem *nic_base = ei_local->mem; + char *buf = skb->data; + + if (ei_local->dmaing) { + netdev_err(dev, + "DMAing conflict in %s [DMAstat:%d][irqlock:%d]\n", + __func__, + ei_local->dmaing, ei_local->irqlock); + return; + } + + ei_local->dmaing |= 0x01; + + ei_outb(E8390_NODMA + E8390_PAGE0 + E8390_START, nic_base + NE_CMD); + ei_outb(count & 0xff, nic_base + EN0_RCNTLO); + ei_outb(count >> 8, nic_base + EN0_RCNTHI); + ei_outb(ring_offset & 0xff, nic_base + EN0_RSARLO); + ei_outb(ring_offset >> 8, nic_base + EN0_RSARHI); + ei_outb(E8390_RREAD + E8390_START, nic_base + NE_CMD); + + xs100_read(dev, buf, count); + + ei_local->dmaing &= ~1; +} + +static void xs100_block_output(struct net_device *dev, int count, + const unsigned char *buf, const int start_page) +{ + struct ei_device *ei_local = netdev_priv(dev); + void __iomem *nic_base = ei_local->mem; + unsigned long dma_start; + + /* Round the count up for word writes. Do we need to do this? + * What effect will an odd byte count have on the 8390? I + * should check someday. + */ + if (ei_local->word16 && (count & 0x01)) + count++; + + /* This *shouldn't* happen. If it does, it's the last thing + * you'll see + */ + if (ei_local->dmaing) { + netdev_err(dev, + "DMAing conflict in %s [DMAstat:%d][irqlock:%d]\n", + __func__, + ei_local->dmaing, ei_local->irqlock); + return; + } + + ei_local->dmaing |= 0x01; + /* We should already be in page 0, but to be safe... */ + ei_outb(E8390_PAGE0 + E8390_START + E8390_NODMA, nic_base + NE_CMD); + + ei_outb(ENISR_RDC, nic_base + EN0_ISR); + + /* Now the normal output. */ + ei_outb(count & 0xff, nic_base + EN0_RCNTLO); + ei_outb(count >> 8, nic_base + EN0_RCNTHI); + ei_outb(0x00, nic_base + EN0_RSARLO); + ei_outb(start_page, nic_base + EN0_RSARHI); + + ei_outb(E8390_RWRITE + E8390_START, nic_base + NE_CMD); + + xs100_write(dev, buf, count); + + dma_start = jiffies; + + while ((ei_inb(nic_base + EN0_ISR) & ENISR_RDC) == 0) { + if (jiffies - dma_start > 2 * HZ / 100) { /* 20ms */ + netdev_warn(dev, "timeout waiting for Tx RDC.\n"); + ei_local->reset_8390(dev); + ax_NS8390_init(dev, 1); + break; + } + } + + ei_outb(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ + ei_local->dmaing &= ~0x01; +} + +static int xsurf100_probe(struct zorro_dev *zdev, + const struct zorro_device_id *ent) +{ + struct platform_device *pdev; + struct xsurf100_ax_plat_data ax88796_data; + struct resource res[2] = { + DEFINE_RES_NAMED(IRQ_AMIGA_PORTS, 1, NULL, + IORESOURCE_IRQ | IORESOURCE_IRQ_SHAREABLE), + DEFINE_RES_MEM(zdev->resource.start + XS100_8390_BASE, + 4 * 0x20) + }; + int reg; + /* This table is referenced in the device structure, so it must + * outlive the scope of xsurf100_probe. + */ + static u32 reg_offsets[32]; + int ret = 0; + + /* X-Surf 100 control and 32 bit ring buffer data access areas. + * These resources are not used by the ax88796 driver, so must + * be requested here and passed via platform data. + */ + + if (!request_mem_region(zdev->resource.start, 0x100, zdev->name)) { + dev_err(&zdev->dev, "cannot reserve X-Surf 100 control registers\n"); + return -ENXIO; + } + + if (!request_mem_region(zdev->resource.start + + XS100_8390_DATA32_BASE, + XS100_8390_DATA32_SIZE, + "X-Surf 100 32-bit data access")) { + dev_err(&zdev->dev, "cannot reserve 32-bit area\n"); + ret = -ENXIO; + goto exit_req; + } + + for (reg = 0; reg < 0x20; reg++) + reg_offsets[reg] = 4 * reg; + + memset(&ax88796_data, 0, sizeof(ax88796_data)); + ax88796_data.ax.flags = AXFLG_HAS_EEPROM; + ax88796_data.ax.wordlength = 2; + ax88796_data.ax.dcr_val = 0x48; + ax88796_data.ax.rcr_val = 0x40; + ax88796_data.ax.reg_offsets = reg_offsets; + ax88796_data.ax.check_irq = is_xsurf100_network_irq; + ax88796_data.base_regs = ioremap(zdev->resource.start, 0x100); + + /* error handling for ioremap regs */ + if (!ax88796_data.base_regs) { + dev_err(&zdev->dev, "Cannot ioremap area %pR (registers)\n", + &zdev->resource); + + ret = -ENXIO; + goto exit_req2; + } + + ax88796_data.data_area = ioremap(zdev->resource.start + + XS100_8390_DATA32_BASE, XS100_8390_DATA32_SIZE); + + /* error handling for ioremap data */ + if (!ax88796_data.data_area) { + dev_err(&zdev->dev, + "Cannot ioremap area %pR offset %x (32-bit access)\n", + &zdev->resource, XS100_8390_DATA32_BASE); + + ret = -ENXIO; + goto exit_mem; + } + + ax88796_data.ax.block_output = xs100_block_output; + ax88796_data.ax.block_input = xs100_block_input; + + pdev = platform_device_register_resndata(&zdev->dev, "ax88796", + zdev->slotaddr, res, 2, + &ax88796_data, + sizeof(ax88796_data)); + + if (IS_ERR(pdev)) { + dev_err(&zdev->dev, "cannot register platform device\n"); + ret = -ENXIO; + goto exit_mem2; + } + + zorro_set_drvdata(zdev, pdev); + + if (!ret) + return 0; + + exit_mem2: + iounmap(ax88796_data.data_area); + + exit_mem: + iounmap(ax88796_data.base_regs); + + exit_req2: + release_mem_region(zdev->resource.start + XS100_8390_DATA32_BASE, + XS100_8390_DATA32_SIZE); + + exit_req: + release_mem_region(zdev->resource.start, 0x100); + + return ret; +} + +static void xsurf100_remove(struct zorro_dev *zdev) +{ + struct platform_device *pdev = zorro_get_drvdata(zdev); + struct xsurf100_ax_plat_data *xs100 = dev_get_platdata(&pdev->dev); + + platform_device_unregister(pdev); + + iounmap(xs100->base_regs); + release_mem_region(zdev->resource.start, 0x100); + iounmap(xs100->data_area); + release_mem_region(zdev->resource.start + XS100_8390_DATA32_BASE, + XS100_8390_DATA32_SIZE); +} + +static const struct zorro_device_id xsurf100_zorro_tbl[] = { + { ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF100, }, + { 0 } +}; + +MODULE_DEVICE_TABLE(zorro, xsurf100_zorro_tbl); + +static struct zorro_driver xsurf100_driver = { + .name = "xsurf100", + .id_table = xsurf100_zorro_tbl, + .probe = xsurf100_probe, + .remove = xsurf100_remove, +}; + +module_driver(xsurf100_driver, zorro_register_driver, zorro_unregister_driver); + +MODULE_DESCRIPTION("X-Surf 100 driver"); +MODULE_AUTHOR("Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de>"); +MODULE_LICENSE("GPL v2"); -- 1.7.0.4
Hi,
messed up the subject there, sorry - this was meant to be
[PATCH v4 0/9] net-next: New network driver for Amiga X-Surf 100 (m68k)
Cheers,
Michael
Am 19.04.2018 um 14:05 schrieb Michael Schmitz:
> [This is a resend of my v3 series which was based on the wrong version and
> tree. Only substantial change is to Asix AX99796B PHY driver.]
>
> This patch series adds support for the Individual Computers X-Surf 100
> network card for m68k Amiga, a network adapter based on the AX88796 chip set.
>
> The driver was originally written for kernel version 3.19 by Michael Karcher
> (see CC:), and adapted to 4.16+ for submission to netdev by me. Questions
> regarding motivation for some of the changes are probably best directed at
> Michael Karcher.
>
> The driver has been tested by Adrian <glaubitz@physik.fu-berlin.de> who will
> send his Tested-by tag separately.
>
> A few changes to the ax88796 driver were required:
> - to read the MAC address, some setup of the ax99796 chip must be done,
> - attach to the MII bus only on device open to allow module unloading,
> - allow to supersede ax_block_input/ax_block_output by card-specific
> optimized code,
> - use an optional interrupt status callback to allow easier sharing of the
> card interrupt,
> - set IRQF_SHARED if platform IRQ resource is marked shareable
>
> The Asix Electronix PHY used on the X-Surf 100 is buggy, and causes the
> software reset to hang if the previous command sent to the PHY was also
> a soft reset. This bug requires addition of a PHY driver for Asix PHYs
> to provide a fixed .soft_reset function, included in this series.
>
> Some additional cleanup:
> - do not attempt to free IRQ in ax_remove (complements 82533ad9a1c),
> - clear platform drvdata on probe fail and module remove.
>
> Changes since v1:
>
> Raised in review by Andrew Lunn:
> - move MII code around to avoid need for forward declaration,
> - combine patches 2 and 7 to add cleanup in error path
>
> Changes since v2:
>
> - corrected authorship attribution to Michael Karcher
>
> Suggested by Geert Uytterhoeven:
> - use ei_local->reset_8390() instead of duplicating ax_reset_8390(),
> - use %pR to format struct resource pointers,
> - assign pdev and xs100 pointers in declaration,
> - don't split error messages,
> - change Kconfig logic to only require XSURF100 set on Amiga
>
> Suggested by Andrew Lunn:
> - add COMPILE_TEST to ax88796 Kconfig options,
> - use new Asix PHY driver for X-Surf 100
>
> Suggested by Andrew Lunn/Finn Thain:
> - declare struct sk_buff in ax88796.h,
> - correct whitespace error in ax88796.h
>
> Changes since v3:
>
> - various checkpatch cleanup
>
> Andrew Lunn:
> - don't duplicate genphy_soft_reset in Asix PHY driver, just call
> genphy_soft_reset after writing zero to control register
>
> This series' patches, in order:
>
> 1/9 net-next: phy: new Asix Electronics PHY driver
> 2/9 net-next: ax88796: Fix MAC address reading
> 3/9 net-next: ax88796: Attach MII bus only when open
> 4/9 net-next: ax88796: Do not free IRQ in ax_remove() (already freed in ax_close()).
> 5/9 net-next: ax88796: Add block_input/output hooks to ax_plat_data
> 6/9 net-next: ax88796: add interrupt status callback to platform data
> 7/9 net-next: ax88796: set IRQF_SHARED flag when IRQ resource is marked as shareable
> 8/9 net-next: ax88796: release platform device drvdata on probe error and module remove
> 9/9 net-next: New ax88796 platform driver for Amiga X-Surf 100 Zorro board (m68k)
>
> drivers/net/ethernet/8390/Kconfig | 17 ++-
> drivers/net/ethernet/8390/Makefile | 1 +
> drivers/net/ethernet/8390/ax88796.c | 228 ++++++++++++--------
> drivers/net/ethernet/8390/xsurf100.c | 382 ++++++++++++++++++++++++++++++++++
> drivers/net/phy/Kconfig | 6 +
> drivers/net/phy/Makefile | 1 +
> drivers/net/phy/asix.c | 63 ++++++
> include/net/ax88796.h | 14 ++
> 8 files changed, 617 insertions(+), 95 deletions(-)
>
> Cheers,
>
> Michael
>
On Thu, Apr 19, 2018 at 02:05:18PM +1200, Michael Schmitz wrote:
> The Asix Electronics PHY found on the X-Surf 100 Amiga Zorro network
> card by Individual Computers is buggy, and needs the reset bit toggled
> as workaround to make a PHY soft reset succeed.
>
> Add workaround driver just for this special case.
>
> Suggested in xsurf100 patch series review by Andrew Lunn <andrew@lunn.ch>
>
> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
On 04/18/2018 07:05 PM, Michael Schmitz wrote:
> The Asix Electronics PHY found on the X-Surf 100 Amiga Zorro network
> card by Individual Computers is buggy, and needs the reset bit toggled
> as workaround to make a PHY soft reset succeed.
>
> Add workaround driver just for this special case.
>
> Suggested in xsurf100 patch series review by Andrew Lunn <andrew@lunn.ch>
>
> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com>
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
--
Florian
From: Michael Schmitz <schmitzmic@gmail.com>
Date: Thu, 19 Apr 2018 14:05:17 +1200
> This patch series adds support for the Individual Computers X-Surf 100
> network card for m68k Amiga, a network adapter based on the AX88796 chip set.
Series applied, thank you.
Thanks Dave!
And many thanks to all the reviewers and testers!
Cheers,
Michael
On Fri, Apr 20, 2018 at 8:11 AM, David Miller <davem@davemloft.net> wrote:
> From: Michael Schmitz <schmitzmic@gmail.com>
> Date: Thu, 19 Apr 2018 14:05:17 +1200
>
>> This patch series adds support for the Individual Computers X-Surf 100
>> network card for m68k Amiga, a network adapter based on the AX88796 chip set.
>
> Series applied, thank you.
Hi Michael, On Thu, Apr 19, 2018 at 4:05 AM, Michael Schmitz <schmitzmic@gmail.com> wrote: > From: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> > > Add platform device driver to populate the ax88796 platform data from > information provided by the XSurf100 zorro device driver. The ax88796 > module will be loaded through this module's probe function. > > Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> > Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> This is now commit 861928f4e60e826c ("net-next: New ax88796 platform driver for Amiga X-Surf 100 Zorro board (m68k)"). > --- /dev/null > +++ b/drivers/net/ethernet/8390/xsurf100.c > +#define __NS8390_init ax_NS8390_init [...] > +#include "lib8390.c" drivers/net/ethernet/8390/lib8390.c:202: warning: ‘__ei_open’ defined but not used drivers/net/ethernet/8390/lib8390.c:231: warning: ‘__ei_close’ defined but not used drivers/net/ethernet/8390/lib8390.c:255: warning: ‘__ei_tx_timeout’ defined but not used drivers/net/ethernet/8390/lib8390.c:302: warning: ‘__ei_start_xmit’ defined but not used drivers/net/ethernet/8390/lib8390.c:510: warning: ‘__ei_poll’ defined but not used drivers/net/ethernet/8390/lib8390.c:851: warning: ‘__ei_get_stats’ defined but not used drivers/net/ethernet/8390/lib8390.c:951: warning: ‘__ei_set_multicast_list’ defined but not used drivers/net/ethernet/8390/lib8390.c:989: warning: ‘____alloc_ei_netdev’ defined but not used So I was wondering: why is this file included, as XSURF100 selects AX88796, while ax88796.c includes lib8390.c anyway? Apparently lib8390.c is included for register definitions (provided by 8390.h, and can easily be fixed), and for the __NS8390_init() implementation, called below. > +static void xs100_block_output(struct net_device *dev, int count, > + const unsigned char *buf, const int start_page) > +{ [...] > + while ((ei_inb(nic_base + EN0_ISR) & ENISR_RDC) == 0) { > + if (jiffies - dma_start > 2 * HZ / 100) { /* 20ms */ > + netdev_warn(dev, "timeout waiting for Tx RDC.\n"); > + ei_local->reset_8390(dev); > + ax_NS8390_init(dev, 1); > + break; > + } > + } > + > + ei_outb(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ > + ei_local->dmaing &= ~0x01; > +} Can we get rid of the inclusion of lib8390.c, and the related warnings? Perhaps ax88796.c can export its ax_NS8390_init(), iff the implementation is identical? Or is there a better solution? Thanks! Gr{oetje,eeting}s, Geert -- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds
Hi Geert, Am 08.06.2018 um 02:36 schrieb Geert Uytterhoeven: > Hi Michael, > > On Thu, Apr 19, 2018 at 4:05 AM, Michael Schmitz <schmitzmic@gmail.com> wrote: >> From: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> >> >> Add platform device driver to populate the ax88796 platform data from >> information provided by the XSurf100 zorro device driver. The ax88796 >> module will be loaded through this module's probe function. >> >> Signed-off-by: Michael Karcher <kernel@mkarcher.dialup.fu-berlin.de> >> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> > > This is now commit 861928f4e60e826c ("net-next: New ax88796 platform > driver for Amiga X-Surf 100 Zorro board (m68k)"). > >> --- /dev/null >> +++ b/drivers/net/ethernet/8390/xsurf100.c > >> +#define __NS8390_init ax_NS8390_init > > [...] > >> +#include "lib8390.c" > > drivers/net/ethernet/8390/lib8390.c:202: warning: ‘__ei_open’ defined > but not used > drivers/net/ethernet/8390/lib8390.c:231: warning: ‘__ei_close’ defined > but not used > drivers/net/ethernet/8390/lib8390.c:255: warning: ‘__ei_tx_timeout’ > defined but not used > drivers/net/ethernet/8390/lib8390.c:302: warning: ‘__ei_start_xmit’ > defined but not used > drivers/net/ethernet/8390/lib8390.c:510: warning: ‘__ei_poll’ defined > but not used > drivers/net/ethernet/8390/lib8390.c:851: warning: ‘__ei_get_stats’ > defined but not used > drivers/net/ethernet/8390/lib8390.c:951: warning: > ‘__ei_set_multicast_list’ defined but not used > drivers/net/ethernet/8390/lib8390.c:989: warning: > ‘____alloc_ei_netdev’ defined but not used > Yep, these have been a little annoying... > So I was wondering: why is this file included, as XSURF100 selects AX88796, > while ax88796.c includes lib8390.c anyway? > > Apparently lib8390.c is included for register definitions (provided by > 8390.h, and can easily be fixed), and for the __NS8390_init() > implementation, called below. Mostly the latter. > >> +static void xs100_block_output(struct net_device *dev, int count, >> + const unsigned char *buf, const int start_page) >> +{ > > [...] > >> + while ((ei_inb(nic_base + EN0_ISR) & ENISR_RDC) == 0) { >> + if (jiffies - dma_start > 2 * HZ / 100) { /* 20ms */ >> + netdev_warn(dev, "timeout waiting for Tx RDC.\n"); >> + ei_local->reset_8390(dev); >> + ax_NS8390_init(dev, 1); >> + break; >> + } >> + } >> + >> + ei_outb(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */ >> + ei_local->dmaing &= ~0x01; >> +} > > Can we get rid of the inclusion of lib8390.c, and the related warnings? > Perhaps ax88796.c can export its ax_NS8390_init(), iff the implementation > is identical? Or is there a better solution? __NS8390_init() is declared static in lib8390.c, and we'd have to change that. I don't think that will fly. Adding a wrapper to ax88796.c that gets exported to the xsurf100 module might be an option - I'll see what I can come up with. Cheers, Michael > > Thanks! > > Gr{oetje,eeting}s, > > Geert >
Let me add my 2 cents as main author of that code:
Michael Schmitz wrote:
> Am 08.06.2018 um 02:36 schrieb Geert Uytterhoeven:
>> So I was wondering: why is this file included, as XSURF100 selects
>> AX88796,
>> while ax88796.c includes lib8390.c anyway?
>>
>> Apparently lib8390.c is included for register definitions (provided by
>> 8390.h, and can easily be fixed), and for the __NS8390_init()
>> implementation, called below.
>
> Mostly the latter.
>
>>
>>> +static void xs100_block_output(struct net_device *dev, int count,
>>> + const unsigned char *buf, const int
>>> start_page)
>>> +{
>>
>> [...]
>>
>>> + while ((ei_inb(nic_base + EN0_ISR) & ENISR_RDC) == 0) {
>>> + if (jiffies - dma_start > 2 * HZ / 100) { /* 20ms
>>> */
>>> + netdev_warn(dev, "timeout waiting for Tx
>>> RDC.\n");
>>> + ei_local->reset_8390(dev);
>>> + ax_NS8390_init(dev, 1);
>>> + break;
>>> + }
>>> + }
>>> +
>>> + ei_outb(ENISR_RDC, nic_base + EN0_ISR); /* Ack intr. */
>>> + ei_local->dmaing &= ~0x01;
>>> +}
actually, the the block_input / block_output functions were the reason I
included the lib8390.c file. Except for xs100_write / xs100_read, they are
a verbatim copy from ax88796.c I'm not that enthusiastic about that idea
anymore, but did not get around to improve it. I added a customization
point to ax88796 for a custom block_input / block_output, because the 8390
core already provides that customization point. What I really need is a
customization point just for the 8390-remote-DMA-via-MMIO functions (i.e.
xs100_write, xs100_read) instead of the whole block transfer core that
also sets up the remote DMA engine and tries to re-initialize the card in
case of unexplained problems.
This should get rid of
- xs100_block_output
- xs100_block_input (which has the calls to ax_reset_8390 and
ax_NS8390_init)
- ax_reset_8390
- and thus the include of lib8390.c (which should be included only by
ax88796.c, not by xsurf100.c)
Regards,
Michael Karcher
Hi Michael, Am 08.06.2018 um 21:28 schrieb Michael Karcher: > Let me add my 2 cents as main author of that code: ... > > actually, the the block_input / block_output functions were the reason I > included the lib8390.c file. Except for xs100_write / xs100_read, they are > a verbatim copy from ax88796.c I'm not that enthusiastic about that idea > anymore, but did not get around to improve it. I added a customization > point to ax88796 for a custom block_input / block_output, because the 8390 > core already provides that customization point. What I really need is a > customization point just for the 8390-remote-DMA-via-MMIO functions (i.e. > xs100_write, xs100_read) instead of the whole block transfer core that > also sets up the remote DMA engine and tries to re-initialize the card in > case of unexplained problems. OK, so essentially change if (ei_local->word16) { ioread16_rep(nic_base + NE_DATAPORT, buf, count >> 1); if (count & 0x01) buf[count-1] = ei_inb(nic_base + NE_DATAPORT); } else { ioread8_rep(nic_base + NE_DATAPORT, buf, count); } to something like if (ax->block_read) { ax->block_read(dev, buf, count); } else if (ei_local->word16) { ioread16_rep(nic_base + NE_DATAPORT, buf, count >> 1); if (count & 0x01) buf[count-1] = ei_inb(nic_base + NE_DATAPORT); } else { ioread8_rep(nic_base + NE_DATAPORT, buf, count); } and populate ax->block_read() and ax_block_write() from platform data, instead of substituting ax_block_input() / ax_block_output() wholesale? I must be missing something here. > This should get rid of > - xs100_block_output > - xs100_block_input (which has the calls to ax_reset_8390 and > ax_NS8390_init) > - ax_reset_8390 > - and thus the include of lib8390.c (which should be included only by > ax88796.c, not by xsurf100.c) I've got an (untested) patch that just exports ax_NS8390_init() via the ax_device struct, and gets rid of the lib8390.c include that way, but the above solution would be a lot cleaner. Adds one test for ax->block_read on the critical path but we already have the test for ei_local->word16 there. May need rearranging the tests so the majority of ax88796 users isn't impacted. Anyway, your code, your call. Cheers, Michael > > Regards, > Michael Karcher >
As suggested by Geert, xsurf100.c really does not need to duplicate code from lib8390.c which is already part of ax88796.c, by including that file. All we need from lib8390.c in the xsurf100 block output function is one single function: ax_NS8390_init(). Export this symbol in ax88796.c so the xsurf100 driver can use it. This is rather a quick band-aid fix to deal with the ugliest code duplication (including lib8390.c where it really isn't needed). The xsurf100 block_input and block_output functiond are almost exact duplicated of the generic ax88796 functions, and changing those to make use of platform-specific block MMIO transfer functions might be a better way to fix this issue. Tested on Amiga hardware (elgar). Cheers, Michael
The block I/O code for the new X-Surf 100 ax88796 driver needs ax_NS8390_init() for error fixup in its block_output function. Export this function so we can lose the lib8380.c include in the X-Surf 100 driver. Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> --- drivers/net/ethernet/8390/ax88796.c | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index 2a0ddec..470142f 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -62,6 +62,8 @@ #include "lib8390.c" +EXPORT_SYMBOL_GPL(ax_NS8390_init); + #define DRV_NAME "ax88796" #define DRV_VERSION "1.00" -- 1.7.0.4
Now that ax88796.c exports the ax_NS8390_init() symbol, we can include 8390.h instead of lib8390.c, avoiding duplication of that function and killing a few compile warnings in the bargain. Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> --- drivers/net/ethernet/8390/xsurf100.c | 10 +++------- 1 files changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/8390/xsurf100.c b/drivers/net/ethernet/8390/xsurf100.c index 4c6f9cb..32caa5e 100644 --- a/drivers/net/ethernet/8390/xsurf100.c +++ b/drivers/net/ethernet/8390/xsurf100.c @@ -33,8 +33,6 @@ #define HW_CHIPID 0x70 #define HW_SCRATCH 0x78 -#define __NS8390_init ax_NS8390_init - /* force unsigned long back to 'void __iomem *' */ #define ax_convert_addr(_a) ((void __force __iomem *)(_a)) @@ -80,12 +78,10 @@ static void reg_write16(void __iomem *base, u16 reg, u16 val) writew(val, base + reg*4); } +#define NS8390_CORE +#include "8390.h" - -static unsigned char version[] = - "ax88796.c: Copyright 2005,2007 Simtec Electronics\n"; - -#include "lib8390.c" +extern void ax_NS8390_init(struct net_device *dev, int startp); /* from ne.c */ #define NE_CMD EI_SHIFT(0x00) -- 1.7.0.4
Michael Schmitz schrieb: > Hi Michael, >> actually, the the block_input / block_output functions were the reason I >> included the lib8390.c file. Except for xs100_write / xs100_read, they >> are >> a verbatim copy from ax88796.c I'm not that enthusiastic about that idea >> anymore, but did not get around to improve it. I added a customization >> point to ax88796 for a custom block_input / block_output, because the >> 8390 >> core already provides that customization point. What I really need is a >> customization point just for the 8390-remote-DMA-via-MMIO functions >> (i.e. >> xs100_write, xs100_read) instead of the whole block transfer core that >> also sets up the remote DMA engine and tries to re-initialize the card >> in >> case of unexplained problems. > > OK, so essentially change > > if (ei_local->word16) { > ioread16_rep(nic_base + NE_DATAPORT, buf, count >> 1); > if (count & 0x01) > buf[count-1] = ei_inb(nic_base + NE_DATAPORT); > > } else { > ioread8_rep(nic_base + NE_DATAPORT, buf, count); > } > > to something like > > if (ax->block_read) { > ax->block_read(dev, buf, count); > } else if (ei_local->word16) { > ioread16_rep(nic_base + NE_DATAPORT, buf, count >> 1); > if (count & 0x01) > buf[count-1] = ei_inb(nic_base + NE_DATAPORT); > > } else { > ioread8_rep(nic_base + NE_DATAPORT, buf, count); > } > > and populate ax->block_read() and ax_block_write() from platform data, > instead of substituting ax_block_input() / ax_block_output() wholesale? That's basically how I think the whole lib8390.c story should in fact be tackled. Less code duplication, no second include of lib8390 and constrain xsurf100.c to the pieces that make this piece of hardware unique. > I must be missing something here. I don't think so. > Adds one test for > ax->block_read on the critical path but we already have the test for > ei_local->word16 there. May need rearranging the tests so the majority > of ax88796 users isn't impacted. Rearranging sounds like a good idea. As I understand, the only valid rearrangement is putting it inside the 16-bit branch, because the xs100 uses 16-bit transfers and needs the extra byte for odd counts. The code checks word16 at the beginning of xs100_block_output for that. This has the advantage of not hurting users of the 8 bit interface, which might be the slowest users of the ax88796, but comes at the cost of not being able to customize the block_input/block_output for 8-bit users. As this "cost" is not a problem now (no one can customize block_input/block_output currently), lets put the block_read check into the word16 block. You might want to name the member block_read16 instead of just block_read to convey the information, that it is only used if word16 is set. > Anyway, your code, your call. On the other hand: Your polishing, your call. Thank you for your work on gettting the code in good shape for merging. Kind regards, Michael Karcher
Hi Michael, On Sat, Jun 9, 2018 at 7:58 AM Michael Schmitz <schmitzmic@gmail.com> wrote: > The block I/O code for the new X-Surf 100 ax88796 driver needs > ax_NS8390_init() for error fixup in its block_output function. > > Export this function so we can lose the lib8380.c include in the > X-Surf 100 driver. > > Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> Thanks for your patch! > --- a/drivers/net/ethernet/8390/ax88796.c > +++ b/drivers/net/ethernet/8390/ax88796.c > @@ -62,6 +62,8 @@ > > #include "lib8390.c" > > +EXPORT_SYMBOL_GPL(ax_NS8390_init); While that works for the modular case, it doesn't work for the builtin case, as the function is static. You can fix that by adding a non-static wrapper, and exporting that one instead. Gr{oetje,eeting}s, Geert -- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds
Hi Michael, On Sat, Jun 9, 2018 at 7:58 AM Michael Schmitz <schmitzmic@gmail.com> wrote: > > Now that ax88796.c exports the ax_NS8390_init() symbol, we can > include 8390.h instead of lib8390.c, avoiding duplication of that > function and killing a few compile warnings in the bargain. > > Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> Thanks for your patch! > --- a/drivers/net/ethernet/8390/xsurf100.c > +++ b/drivers/net/ethernet/8390/xsurf100.c > @@ -33,8 +33,6 @@ > #define HW_CHIPID 0x70 > #define HW_SCRATCH 0x78 > > -#define __NS8390_init ax_NS8390_init > - > /* force unsigned long back to 'void __iomem *' */ > #define ax_convert_addr(_a) ((void __force __iomem *)(_a)) > > @@ -80,12 +78,10 @@ static void reg_write16(void __iomem *base, u16 reg, u16 val) This doesn't apply against net-next, which doesn't have reg_write16() (yet?). Apart from that, your patch looks fine to me. Gr{oetje,eeting}s, Geert -- Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org In personal conversations with technical people, I call myself a hacker. But when I'm talking to journalists I just say "programmer" or something like that. -- Linus Torvalds
Hi Geert, Am 10.06.2018 um 02:33 schrieb Geert Uytterhoeven: > Hi Michael, > > On Sat, Jun 9, 2018 at 7:58 AM Michael Schmitz <schmitzmic@gmail.com> wrote: >> >> Now that ax88796.c exports the ax_NS8390_init() symbol, we can >> include 8390.h instead of lib8390.c, avoiding duplication of that >> function and killing a few compile warnings in the bargain. >> >> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> > > Thanks for your patch! > > >> --- a/drivers/net/ethernet/8390/xsurf100.c >> +++ b/drivers/net/ethernet/8390/xsurf100.c >> @@ -33,8 +33,6 @@ >> #define HW_CHIPID 0x70 >> #define HW_SCRATCH 0x78 >> >> -#define __NS8390_init ax_NS8390_init >> - >> /* force unsigned long back to 'void __iomem *' */ >> #define ax_convert_addr(_a) ((void __force __iomem *)(_a)) >> >> @@ -80,12 +78,10 @@ static void reg_write16(void __iomem *base, u16 reg, u16 val) > > This doesn't apply against net-next, which doesn't have reg_write16() (yet?). Bummer - that's from my experimental ISP1173 probe code, nothing to do with network code. I'll redo these patches against net-next (and add a non-static wrapper for ax_NS8390_init to allow compiling in the driver). Thanks, Michael > Apart from that, your patch looks fine to me. > > Gr{oetje,eeting}s, > > Geert >
Hi Michael, Am 09.06.2018 um 21:15 schrieb Michael Karcher: > Michael Schmitz schrieb: >> Hi Michael, >>> actually, the the block_input / block_output functions were the reason I >>> included the lib8390.c file. Except for xs100_write / xs100_read, they >>> are >>> a verbatim copy from ax88796.c I'm not that enthusiastic about that idea >>> anymore, but did not get around to improve it. I added a customization >>> point to ax88796 for a custom block_input / block_output, because the >>> 8390 >>> core already provides that customization point. What I really need is a >>> customization point just for the 8390-remote-DMA-via-MMIO functions >>> (i.e. >>> xs100_write, xs100_read) instead of the whole block transfer core that >>> also sets up the remote DMA engine and tries to re-initialize the card >>> in >>> case of unexplained problems. >> >> OK, so essentially change >> >> if (ei_local->word16) { >> ioread16_rep(nic_base + NE_DATAPORT, buf, count >> 1); >> if (count & 0x01) >> buf[count-1] = ei_inb(nic_base + NE_DATAPORT); >> >> } else { >> ioread8_rep(nic_base + NE_DATAPORT, buf, count); >> } >> >> to something like >> >> if (ax->block_read) { >> ax->block_read(dev, buf, count); >> } else if (ei_local->word16) { >> ioread16_rep(nic_base + NE_DATAPORT, buf, count >> 1); >> if (count & 0x01) >> buf[count-1] = ei_inb(nic_base + NE_DATAPORT); >> >> } else { >> ioread8_rep(nic_base + NE_DATAPORT, buf, count); >> } >> >> and populate ax->block_read() and ax_block_write() from platform data, >> instead of substituting ax_block_input() / ax_block_output() wholesale? > > That's basically how I think the whole lib8390.c story should in fact be > tackled. Less code duplication, no second include of lib8390 and constrain > xsurf100.c to the pieces that make this piece of hardware unique. OK, I'll try that. >> I must be missing something here. > > I don't think so. > >> Adds one test for >> ax->block_read on the critical path but we already have the test for >> ei_local->word16 there. May need rearranging the tests so the majority >> of ax88796 users isn't impacted. > Rearranging sounds like a good idea. As I understand, the only valid > rearrangement is putting it inside the 16-bit branch, because the xs100 > uses 16-bit transfers and needs the extra byte for odd counts. The code Thanks, I missed that. > checks word16 at the beginning of xs100_block_output for that. This has > the advantage of not hurting users of the 8 bit interface, which might be > the slowest users of the ax88796, but comes at the cost of not being able > to customize the block_input/block_output for 8-bit users. As this "cost" > is not a problem now (no one can customize block_input/block_output > currently), lets put the block_read check into the word16 block. You might > want to name the member block_read16 instead of just block_read to convey > the information, that it is only used if word16 is set. Fair enough - since any block_input/block_output function always needs to duplicate quite a bit of 8390 control code, this might be easier. I'll have to ask Adrian to set up something for me to run speed tests on though, to see any eventual impact of these changes. Cheers, Michael >> Anyway, your code, your call. > On the other hand: Your polishing, your call. Thank you for your work on > gettting the code in good shape for merging. > > Kind regards, > Michael Karcher >
As suggested by Geert, xsurf100.c really does not need to duplicate code from lib8390.c which is already part of ax88796.c, by including that file. All we need from lib8390.c in the xsurf100 block output function is one single function: ax_NS8390_init(). Export this symbol through a wrapper in ax88796.c (the original __NS8390_init() is a static function) so the xsurf100 driver can use it. This is rather a quick band-aid fix to deal with the ugliest code duplication (including lib8390.c where it really isn't needed). The xsurf100 block_input and block_output functions are almost exact duplicates of the generic ax88796 functions, and changing those to make use of platform-specific block MMIO transfer functions would allow all duplicated code to be removed from xsurf100.c. This will be addressed in a later patch. Changes from earlier RFC version: - rebased on net-next so patch 2 applies cleanly - use a non-static wrapper for ax_NS8390_init() alias __NS8390_init() so this driver can be compiled in. Tested on Amiga hardware (elgar). Cheers, Michael
The block I/O code for the new X-Surf 100 ax88796 driver needs ax_NS8390_init() for error fixup in its block_output function. Export this static function through the ax_NS8390_reinit() wrapper so we can lose the lib8380.c include in the X-Surf 100 driver. Fixes: 861928f4e60e826c ("net-next: New ax88796 platform driver for Amiga X-Surf 100 Zorro board (m68k)") Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> --- drivers/net/ethernet/8390/ax88796.c | 7 +++++++ 1 files changed, 7 insertions(+), 0 deletions(-) diff --git a/drivers/net/ethernet/8390/ax88796.c b/drivers/net/ethernet/8390/ax88796.c index 2a0ddec..673d154 100644 --- a/drivers/net/ethernet/8390/ax88796.c +++ b/drivers/net/ethernet/8390/ax88796.c @@ -104,6 +104,13 @@ struct ax_device { return (struct ax_device *)(ei_local + 1); } +void ax_NS8390_reinit(struct net_device *dev) +{ + ax_NS8390_init(dev, 1); +} + +EXPORT_SYMBOL_GPL(ax_NS8390_reinit); + /* * ax_initial_check * -- 1.7.0.4
Now that ax88796.c exports the ax_NS8390_reinit() symbol, we can include 8390.h instead of lib8390.c, avoiding duplication of that function and killing a few compile warnings in the bargain. Fixes: 861928f4e60e826c ("net-next: New ax88796 platform driver for Amiga X-Surf 100 Zorro board (m68k)") Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> --- drivers/net/ethernet/8390/xsurf100.c | 11 +++++------ 1 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/8390/xsurf100.c b/drivers/net/ethernet/8390/xsurf100.c index e2c9638..1c3e8d1 100644 --- a/drivers/net/ethernet/8390/xsurf100.c +++ b/drivers/net/ethernet/8390/xsurf100.c @@ -22,8 +22,6 @@ #define XS100_8390_DATA_WRITE32_BASE 0x0C80 #define XS100_8390_DATA_AREA_SIZE 0x80 -#define __NS8390_init ax_NS8390_init - /* force unsigned long back to 'void __iomem *' */ #define ax_convert_addr(_a) ((void __force __iomem *)(_a)) @@ -42,10 +40,11 @@ /* Ensure we have our RCR base value */ #define AX88796_PLATFORM -static unsigned char version[] = - "ax88796.c: Copyright 2005,2007 Simtec Electronics\n"; +#define NS8390_CORE +#include "8390.h" -#include "lib8390.c" +/* exported from ax88796.c, especially for our benefit */ +extern void ax_NS8390_reinit(struct net_device *dev); /* from ne.c */ #define NE_CMD EI_SHIFT(0x00) @@ -232,7 +231,7 @@ static void xs100_block_output(struct net_device *dev, int count, if (jiffies - dma_start > 2 * HZ / 100) { /* 20ms */ netdev_warn(dev, "timeout waiting for Tx RDC.\n"); ei_local->reset_8390(dev); - ax_NS8390_init(dev, 1); + ax_NS8390_reinit(dev); break; } } -- 1.7.0.4
Hi Michael,
Thanks for the update!
On Sun, Jun 10, 2018 at 6:22 AM Michael Schmitz <schmitzmic@gmail.com> wrote:
> The block I/O code for the new X-Surf 100 ax88796 driver needs
> ax_NS8390_init() for error fixup in its block_output function.
>
> Export this static function through the ax_NS8390_reinit()
> wrapper so we can lose the lib8380.c include in the X-Surf 100
> driver.
>
> Fixes: 861928f4e60e826c ("net-next: New ax88796 platform
> driver for Amiga X-Surf 100 Zorro board (m68k)")
>
> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com>
Reviewed-by: Geert Uytterhoeven <geert@linux-m68k.org>
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
On Sun, Jun 10, 2018 at 6:22 AM Michael Schmitz <schmitzmic@gmail.com> wrote:
> Now that ax88796.c exports the ax_NS8390_reinit() symbol, we can
> include 8390.h instead of lib8390.c, avoiding duplication of that
> function and killing a few compile warnings in the bargain.
>
> Fixes: 861928f4e60e826c ("net-next: New ax88796 platform
> driver for Amiga X-Surf 100 Zorro board (m68k)")
>
> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com>
Reviewed-by: Geert Uytterhoeven <geert@linux-m68k.org>
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
Michael,
On Thu, 19 Apr 2018, Michael Schmitz wrote:
> --- /dev/null
> +++ b/drivers/net/phy/asix.c
> @@ -0,0 +1,63 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/* Driver for Asix PHYs
> + *
> + * Author: Michael Schmitz <schmitzmic@gmail.com>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the
> + * Free Software Foundation; either version 2 of the License, or (at your
> + * option) any later version.
> + *
> + */
This license information is broken. The SPDX license identifier and the
boiler plate text are contradicting. The SPDX id is GPL v2 only and the
boiler plate says v2 or later.
Please decide which version you want and fix ASAP. If you fix that up
please add a Fixes: tag and cc stable. While at it please remove the boiler
plate text as the SPDX id is sufficient and the boiler plate is redundant
information.
See Documentation/process/license-rules.txt
Thanks,
tglx
On Fri, Jan 18, 2019 at 11:22:39AM +0100, Thomas Gleixner wrote: > Michael, > > On Thu, 19 Apr 2018, Michael Schmitz wrote: > > > --- /dev/null > > +++ b/drivers/net/phy/asix.c > > @@ -0,0 +1,63 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* Driver for Asix PHYs > > + * > > + * Author: Michael Schmitz <schmitzmic@gmail.com> > > + * > > + * This program is free software; you can redistribute it and/or modify it > > + * under the terms of the GNU General Public License as published by the > > + * Free Software Foundation; either version 2 of the License, or (at your > > + * option) any later version. > > + * > > + */ > > This license information is broken. The SPDX license identifier and the > boiler plate text are contradicting. The SPDX id is GPL v2 only and the > boiler plate says v2 or later. Hi Thomas Please see: https://www.spinics.net/lists/netdev/msg544312.html The first two patches are simple SPDX converstions. Then it gets interesting trying to sort out license inconsistencies. Andrew
Hi Andrew,
no objection for you to pick this up as part as a larger cleanup. I've
tried to reconstruct how this happened (i.e. what other phy driver file
I used as a 'template' for asix.c) - all I can say is that the 2.0+
boiler plate text was in my initial commit, and the incorrect SPDX tag
was added in response to checkpath complaints. So 2.0+ would be correct.
Thomas: does that suit your purpose?
Cheers,
Michael
On 21/01/19 6:43 AM, Andrew Lunn wrote:
> On Fri, Jan 18, 2019 at 11:22:39AM +0100, Thomas Gleixner wrote:
>> Michael,
>>
>> On Thu, 19 Apr 2018, Michael Schmitz wrote:
>>
>>> --- /dev/null
>>> +++ b/drivers/net/phy/asix.c
>>> @@ -0,0 +1,63 @@
>>> +// SPDX-License-Identifier: GPL-2.0
>>> +/* Driver for Asix PHYs
>>> + *
>>> + * Author: Michael Schmitz <schmitzmic@gmail.com>
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify it
>>> + * under the terms of the GNU General Public License as published by the
>>> + * Free Software Foundation; either version 2 of the License, or (at your
>>> + * option) any later version.
>>> + *
>>> + */
>> This license information is broken. The SPDX license identifier and the
>> boiler plate text are contradicting. The SPDX id is GPL v2 only and the
>> boiler plate says v2 or later.
> Hi Thomas
>
> Please see:
>
> https://www.spinics.net/lists/netdev/msg544312.html
>
> The first two patches are simple SPDX converstions. Then it gets
> interesting trying to sort out license inconsistencies.
>
> Andrew
On Sun, Jun 10, 2018 at 6:23 AM Michael Schmitz <schmitzmic@gmail.com> wrote: > > Now that ax88796.c exports the ax_NS8390_reinit() symbol, we can > include 8390.h instead of lib8390.c, avoiding duplication of that > function and killing a few compile warnings in the bargain. > > Fixes: 861928f4e60e826c ("net-next: New ax88796 platform > driver for Amiga X-Surf 100 Zorro board (m68k)") > > Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> > --- > drivers/net/ethernet/8390/xsurf100.c | 11 +++++------ > 1 files changed, 5 insertions(+), 6 deletions(-) Geert noticed that a patch I just sent is similar to this one. Since I assume you have verified this version works, it would be nice if you could resend both patches. Alternatively, I can include them in my series if you like. Reviewed-by: Arnd Bergmann <arnd@arndb.de > diff --git a/drivers/net/ethernet/8390/xsurf100.c b/drivers/net/ethernet/8390/xsurf100.c > index e2c9638..1c3e8d1 100644 > --- a/drivers/net/ethernet/8390/xsurf100.c > +++ b/drivers/net/ethernet/8390/xsurf100.c > @@ -22,8 +22,6 @@ > #define XS100_8390_DATA_WRITE32_BASE 0x0C80 > #define XS100_8390_DATA_AREA_SIZE 0x80 > > -#define __NS8390_init ax_NS8390_init > - > /* force unsigned long back to 'void __iomem *' */ > #define ax_convert_addr(_a) ((void __force __iomem *)(_a)) > > @@ -42,10 +40,11 @@ > /* Ensure we have our RCR base value */ > #define AX88796_PLATFORM > > -static unsigned char version[] = > - "ax88796.c: Copyright 2005,2007 Simtec Electronics\n"; > +#define NS8390_CORE > +#include "8390.h" I don't see that #define being referenced anywhere, can that be dropped? Arnd
Hi Arnd, Am 16.05.2021 um 21:52 schrieb Arnd Bergmann: > On Sun, Jun 10, 2018 at 6:23 AM Michael Schmitz <schmitzmic@gmail.com> wrote: >> >> Now that ax88796.c exports the ax_NS8390_reinit() symbol, we can >> include 8390.h instead of lib8390.c, avoiding duplication of that >> function and killing a few compile warnings in the bargain. >> >> Fixes: 861928f4e60e826c ("net-next: New ax88796 platform >> driver for Amiga X-Surf 100 Zorro board (m68k)") >> >> Signed-off-by: Michael Schmitz <schmitzmic@gmail.com> >> --- >> drivers/net/ethernet/8390/xsurf100.c | 11 +++++------ >> 1 files changed, 5 insertions(+), 6 deletions(-) > > Geert noticed that a patch I just sent is similar to this one. Since I assume > you have verified this version works, it would be nice if you could resend > both patches. Oh dear - I had all but forgotten about this one. The patch announcement states it was tested on elgar so yes, this version works. These patches originated in a review comment by Geert for the original xsurf100 driver that came after Dave had accepted the driver. Might even have been misrouted by me (I wasn't very clear whether net or net-next was appropriate). I evidently never followed up. Which reminds me to check how far we ever got with testing the XSurf500 driver that's still stuck in my tree. > Alternatively, I can include them in my series if you like. Please do that - I haven't followed net-next for over a year and don't have a current enough tree to rebase this on. > Reviewed-by: Arnd Bergmann <arnd@arndb.de > >> diff --git a/drivers/net/ethernet/8390/xsurf100.c b/drivers/net/ethernet/8390/xsurf100.c >> index e2c9638..1c3e8d1 100644 >> --- a/drivers/net/ethernet/8390/xsurf100.c >> +++ b/drivers/net/ethernet/8390/xsurf100.c >> @@ -22,8 +22,6 @@ >> #define XS100_8390_DATA_WRITE32_BASE 0x0C80 >> #define XS100_8390_DATA_AREA_SIZE 0x80 >> >> -#define __NS8390_init ax_NS8390_init >> - >> /* force unsigned long back to 'void __iomem *' */ >> #define ax_convert_addr(_a) ((void __force __iomem *)(_a)) >> >> @@ -42,10 +40,11 @@ >> /* Ensure we have our RCR base value */ >> #define AX88796_PLATFORM >> >> -static unsigned char version[] = >> - "ax88796.c: Copyright 2005,2007 Simtec Electronics\n"; >> +#define NS8390_CORE >> +#include "8390.h" > > I don't see that #define being referenced anywhere, can that be dropped? Can't find it used anywhere either, so I'm confident it can be dropped. While you're at it, I believe it can be dropped from lib8390.c as well now (that's where I copied it from). Dave would know for sure. Cheers, Michael > > Arnd >
On Tue, May 18, 2021 at 10:42 AM Michael Schmitz <schmitzmic@gmail.com> wrote:
>
> Which reminds me to check how far we ever got with testing the XSurf500
> driver that's still stuck in my tree.
>
> > Alternatively, I can include them in my series if you like.
>
> Please do that - I haven't followed net-next for over a year and don't
> have a current enough tree to rebase this on.
Ok, done. I'll send the series once net-next opens for 5.14.
Arnd
Thanks Arnd!
Cheers,
Michael
On 19/05/21 1:56 am, Arnd Bergmann wrote:
> On Tue, May 18, 2021 at 10:42 AM Michael Schmitz <schmitzmic@gmail.com> wrote:
>> Which reminds me to check how far we ever got with testing the XSurf500
>> driver that's still stuck in my tree.
>>
>>> Alternatively, I can include them in my series if you like.
>> Please do that - I haven't followed net-next for over a year and don't
>> have a current enough tree to rebase this on.
> Ok, done. I'll send the series once net-next opens for 5.14.
>
> Arnd