Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fd5f375c authored by Michael Karcher's avatar Michael Karcher Committed by David S. Miller
Browse files

net-next: ax88796: Attach MII bus only when open



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: default avatarMichael Karcher <kernel@mkarcher.dialup.fu-berlin.de>
Signed-off-by: default avatarMichael Schmitz <schmitzmic@gmail.com>
Reviewed-by: default avatarAndrew Lunn <andrew@lunn.ch>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7a0907bd
Loading
Loading
Loading
Loading
+95 −88
Original line number Diff line number Diff line
@@ -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 const struct net_device_ops ax_netdev_ops = {
#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);