Commit 773dc50d authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'Xilinx-axienet-updates'



Robert Hancock says:

====================
Xilinx axienet updates

Updates to the Xilinx AXI Ethernet driver to add support for an additional
ethtool operation, and to support dynamic switching between 1000BaseX and
SGMII interface modes.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 762d17b9 6c8f06bb
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -38,6 +38,10 @@ Optional properties:
		  1 to enable partial TX checksum offload,
		  2 to enable full TX checksum offload
- xlnx,rxcsum	: Same values as xlnx,txcsum but for RX checksum offload
- xlnx,switch-x-sgmii : Boolean to indicate the Ethernet core is configured to
		  support both 1000BaseX and SGMII modes. If set, the phy-mode
		  should be set to match the mode selected on core reset (i.e.
		  by the basex_or_sgmii core input line).
- clocks	: AXI bus clock for the device. Refer to common clock bindings.
		  Used to calculate MDIO clock divisor. If not specified, it is
		  auto-detected from the CPU clock (but only on platforms where
+18 −11
Original line number Diff line number Diff line
@@ -339,6 +339,10 @@

#define DELAY_OF_ONE_MILLISEC		1000

/* Xilinx PCS/PMA PHY register for switching 1000BaseX or SGMII */
#define XLNX_MII_STD_SELECT_REG		0x11
#define XLNX_MII_STD_SELECT_SGMII	BIT(0)

/**
 * struct axidma_bd - Axi Dma buffer descriptor layout
 * @next:         MM2S/S2MM Next Descriptor Pointer
@@ -377,22 +381,29 @@ struct axidma_bd {
 * @ndev:	Pointer for net_device to which it will be attached.
 * @dev:	Pointer to device structure
 * @phy_node:	Pointer to device node structure
 * @phylink:	Pointer to phylink instance
 * @phylink_config: phylink configuration settings
 * @pcs_phy:	Reference to PCS/PMA PHY if used
 * @switch_x_sgmii: Whether switchable 1000BaseX/SGMII mode is enabled in the core
 * @clk:	Clock for AXI bus
 * @mii_bus:	Pointer to MII bus structure
 * @mii_clk_div: MII bus clock divider value
 * @regs_start: Resource start for axienet device addresses
 * @regs:	Base address for the axienet_local device address space
 * @dma_regs:	Base address for the axidma device address space
 * @dma_err_tasklet: Tasklet structure to process Axi DMA errors
 * @dma_err_task: Work structure to process Axi DMA errors
 * @tx_irq:	Axidma TX IRQ number
 * @rx_irq:	Axidma RX IRQ number
 * @eth_irq:	Ethernet core IRQ number
 * @phy_mode:	Phy type to identify between MII/GMII/RGMII/SGMII/1000 Base-X
 * @options:	AxiEthernet option word
 * @last_link:	Phy link state in which the PHY was negotiated earlier
 * @features:	Stores the extended features supported by the axienet hw
 * @tx_bd_v:	Virtual address of the TX buffer descriptor ring
 * @tx_bd_p:	Physical address(start address) of the TX buffer descr. ring
 * @tx_bd_num:	Size of TX buffer descriptor ring
 * @rx_bd_v:	Virtual address of the RX buffer descriptor ring
 * @rx_bd_p:	Physical address(start address) of the RX buffer descr. ring
 * @rx_bd_num:	Size of RX buffer descriptor ring
 * @tx_bd_ci:	Stores the index of the Tx buffer descriptor in the ring being
 *		accessed currently. Used while alloc. BDs before a TX starts
 * @tx_bd_tail:	Stores the index of the Tx buffer descriptor in the ring being
@@ -414,23 +425,20 @@ struct axienet_local {
	struct net_device *ndev;
	struct device *dev;

	/* Connection to PHY device */
	struct device_node *phy_node;

	struct phylink *phylink;
	struct phylink_config phylink_config;

	/* Reference to PCS/PMA PHY if used */
	struct mdio_device *pcs_phy;

	/* Clock for AXI bus */
	bool switch_x_sgmii;

	struct clk *clk;

	/* MDIO bus data */
	struct mii_bus *mii_bus;	/* MII bus reference */
	u8 mii_clk_div; /* MII bus clock divider value */
	struct mii_bus *mii_bus;
	u8 mii_clk_div;

	/* IO registers, dma functions and IRQs */
	resource_size_t regs_start;
	void __iomem *regs;
	void __iomem *dma_regs;
@@ -442,10 +450,9 @@ struct axienet_local {
	int eth_irq;
	phy_interface_t phy_mode;

	u32 options;			/* Current options word */
	u32 options;
	u32 features;

	/* Buffer descriptors */
	struct axidma_bd *tx_bd_v;
	dma_addr_t tx_bd_p;
	u32 tx_bd_num;
+61 −7
Original line number Diff line number Diff line
@@ -1469,6 +1469,13 @@ axienet_ethtools_set_link_ksettings(struct net_device *ndev,
	return phylink_ethtool_ksettings_set(lp->phylink, cmd);
}

static int axienet_ethtools_nway_reset(struct net_device *dev)
{
	struct axienet_local *lp = netdev_priv(dev);

	return phylink_ethtool_nway_reset(lp->phylink);
}

static const struct ethtool_ops axienet_ethtool_ops = {
	.supported_coalesce_params = ETHTOOL_COALESCE_MAX_FRAMES,
	.get_drvinfo    = axienet_ethtools_get_drvinfo,
@@ -1483,6 +1490,7 @@ static const struct ethtool_ops axienet_ethtool_ops = {
	.set_coalesce   = axienet_ethtools_set_coalesce,
	.get_link_ksettings = axienet_ethtools_get_link_ksettings,
	.set_link_ksettings = axienet_ethtools_set_link_ksettings,
	.nway_reset	= axienet_ethtools_nway_reset,
};

static void axienet_validate(struct phylink_config *config,
@@ -1494,14 +1502,23 @@ static void axienet_validate(struct phylink_config *config,
	__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };

	/* Only support the mode we are configured for */
	if (state->interface != PHY_INTERFACE_MODE_NA &&
	    state->interface != lp->phy_mode) {
	switch (state->interface) {
	case PHY_INTERFACE_MODE_NA:
		break;
	case PHY_INTERFACE_MODE_1000BASEX:
	case PHY_INTERFACE_MODE_SGMII:
		if (lp->switch_x_sgmii)
			break;
		fallthrough;
	default:
		if (state->interface != lp->phy_mode) {
			netdev_warn(ndev, "Cannot use PHY mode %s, supported: %s\n",
				    phy_modes(state->interface),
				    phy_modes(lp->phy_mode));
			bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
			return;
		}
	}

	phylink_set(mask, Autoneg);
	phylink_set_port_modes(mask);
@@ -1560,6 +1577,33 @@ static void axienet_mac_an_restart(struct phylink_config *config)
	phylink_mii_c22_pcs_an_restart(lp->pcs_phy);
}

static int axienet_mac_prepare(struct phylink_config *config, unsigned int mode,
			       phy_interface_t iface)
{
	struct net_device *ndev = to_net_dev(config->dev);
	struct axienet_local *lp = netdev_priv(ndev);
	int ret;

	switch (iface) {
	case PHY_INTERFACE_MODE_SGMII:
	case PHY_INTERFACE_MODE_1000BASEX:
		if (!lp->switch_x_sgmii)
			return 0;

		ret = mdiobus_write(lp->pcs_phy->bus,
				    lp->pcs_phy->addr,
				    XLNX_MII_STD_SELECT_REG,
				    iface == PHY_INTERFACE_MODE_SGMII ?
					XLNX_MII_STD_SELECT_SGMII : 0);
		if (ret < 0)
			netdev_warn(ndev, "Failed to switch PHY interface: %d\n",
				    ret);
		return ret;
	default:
		return 0;
	}
}

static void axienet_mac_config(struct phylink_config *config, unsigned int mode,
			       const struct phylink_link_state *state)
{
@@ -1637,6 +1681,7 @@ static const struct phylink_mac_ops axienet_phylink_ops = {
	.validate = axienet_validate,
	.mac_pcs_get_state = axienet_mac_pcs_get_state,
	.mac_an_restart = axienet_mac_an_restart,
	.mac_prepare = axienet_mac_prepare,
	.mac_config = axienet_mac_config,
	.mac_link_down = axienet_mac_link_down,
	.mac_link_up = axienet_mac_link_up,
@@ -1876,6 +1921,9 @@ static int axienet_probe(struct platform_device *pdev)
	 */
	of_property_read_u32(pdev->dev.of_node, "xlnx,rxmem", &lp->rxmem);

	lp->switch_x_sgmii = of_property_read_bool(pdev->dev.of_node,
						   "xlnx,switch-x-sgmii");

	/* Start with the proprietary, and broken phy_type */
	ret = of_property_read_u32(pdev->dev.of_node, "xlnx,phy-type", &value);
	if (!ret) {
@@ -1905,6 +1953,12 @@ static int axienet_probe(struct platform_device *pdev)
		if (ret)
			goto free_netdev;
	}
	if (lp->switch_x_sgmii && lp->phy_mode != PHY_INTERFACE_MODE_SGMII &&
	    lp->phy_mode != PHY_INTERFACE_MODE_1000BASEX) {
		dev_err(&pdev->dev, "xlnx,switch-x-sgmii only supported with SGMII or 1000BaseX\n");
		ret = -EINVAL;
		goto free_netdev;
	}

	/* Find the DMA node, map the DMA registers, and decode the DMA IRQs */
	np = of_parse_phandle(pdev->dev.of_node, "axistream-connected", 0);