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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
773dc50d71
Documentation/devicetree/bindings/net
drivers/net/ethernet/xilinx
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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,13 +1502,22 @@ 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) {
|
||||
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;
|
||||
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);
|
||||
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user