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

Commit 99eee14a authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'cpsw'



Mugunthan V N says:

====================
This patch serires implements the following features in CPSW driver
* get/set phy link settings
* interrupt pacing
* get phy id via ioctl cmd SIOCGMIIPHY

Changes from initial version
* Made active-slave common for cpts, ethtool and SIOCGMIIPHY ioctl
* Cleaned CPSW DT binding documentation by seperating slave nodes
  under sub-section
* implemented get phy id via ioctl cmd SIOCGMIIPHY
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents c1ad32af 11f2c988
Loading
Loading
Loading
Loading
+11 −5
Original line number Diff line number Diff line
@@ -15,16 +15,22 @@ Required properties:
- mac_control		: Specifies Default MAC control register content
			  for the specific platform
- slaves		: Specifies number for slaves
- cpts_active_slave	: Specifies the slave to use for time stamping
- active_slave		: Specifies the slave to use for time stamping,
			  ethtool and SIOCGMIIPHY
- cpts_clock_mult	: Numerator to convert input clock ticks into nanoseconds
- cpts_clock_shift	: Denominator to convert input clock ticks into nanoseconds
- phy_id		: Specifies slave phy id
- mac-address		: Specifies slave MAC address

Optional properties:
- ti,hwmods		: Must be "cpgmac0"
- no_bd_ram		: Must be 0 or 1
- dual_emac		: Specifies Switch to act as Dual EMAC

Slave Properties:
Required properties:
- phy_id		: Specifies slave phy id
- mac-address		: Specifies slave MAC address

Optional properties:
- dual_emac_res_vlan	: Specifies VID to be used to segregate the ports

Note: "ti,hwmods" field is used to fetch the base address and irq
@@ -47,7 +53,7 @@ Examples:
		rx_descs = <64>;
		mac_control = <0x20>;
		slaves = <2>;
		cpts_active_slave = <0>;
		active_slave = <0>;
		cpts_clock_mult = <0x80000000>;
		cpts_clock_shift = <29>;
		cpsw_emac0: slave@0 {
@@ -73,7 +79,7 @@ Examples:
		rx_descs = <64>;
		mac_control = <0x20>;
		slaves = <2>;
		cpts_active_slave = <0>;
		active_slave = <0>;
		cpts_clock_mult = <0x80000000>;
		cpts_clock_shift = <29>;
		cpsw_emac0: slave@0 {
+1 −1
Original line number Diff line number Diff line
@@ -349,7 +349,7 @@
			rx_descs = <64>;
			mac_control = <0x20>;
			slaves = <2>;
			cpts_active_slave = <0>;
			active_slave = <0>;
			cpts_clock_mult = <0x80000000>;
			cpts_clock_shift = <29>;
			reg = <0x4a100000 0x800
+152 −7
Original line number Diff line number Diff line
@@ -126,6 +126,13 @@ do { \
#define CPSW_FIFO_DUAL_MAC_MODE		(1 << 15)
#define CPSW_FIFO_RATE_LIMIT_MODE	(2 << 15)

#define CPSW_INTPACEEN		(0x3f << 16)
#define CPSW_INTPRESCALE_MASK	(0x7FF << 0)
#define CPSW_CMINTMAX_CNT	63
#define CPSW_CMINTMIN_CNT	2
#define CPSW_CMINTMAX_INTVL	(1000 / CPSW_CMINTMIN_CNT)
#define CPSW_CMINTMIN_INTVL	((1000 / CPSW_CMINTMAX_CNT) + 1)

#define cpsw_enable_irq(priv)	\
	do {			\
		u32 i;		\
@@ -139,6 +146,10 @@ do { \
			disable_irq_nosync(priv->irqs_table[i]); \
	} while (0);

#define cpsw_slave_index(priv)				\
		((priv->data.dual_emac) ? priv->emac_port :	\
		priv->data.active_slave)

static int debug_level;
module_param(debug_level, int, 0);
MODULE_PARM_DESC(debug_level, "cpsw debug level (NETIF_MSG bits)");
@@ -160,6 +171,15 @@ struct cpsw_wr_regs {
	u32	rx_en;
	u32	tx_en;
	u32	misc_en;
	u32	mem_allign1[8];
	u32	rx_thresh_stat;
	u32	rx_stat;
	u32	tx_stat;
	u32	misc_stat;
	u32	mem_allign2[8];
	u32	rx_imax;
	u32	tx_imax;

};

struct cpsw_ss_regs {
@@ -314,6 +334,8 @@ struct cpsw_priv {
	struct cpsw_host_regs __iomem	*host_port_regs;
	u32				msg_enable;
	u32				version;
	u32				coal_intvl;
	u32				bus_freq_mhz;
	struct net_device_stats		stats;
	int				rx_packet_max;
	int				host_port;
@@ -612,6 +634,77 @@ static void cpsw_adjust_link(struct net_device *ndev)
	}
}

static int cpsw_get_coalesce(struct net_device *ndev,
				struct ethtool_coalesce *coal)
{
	struct cpsw_priv *priv = netdev_priv(ndev);

	coal->rx_coalesce_usecs = priv->coal_intvl;
	return 0;
}

static int cpsw_set_coalesce(struct net_device *ndev,
				struct ethtool_coalesce *coal)
{
	struct cpsw_priv *priv = netdev_priv(ndev);
	u32 int_ctrl;
	u32 num_interrupts = 0;
	u32 prescale = 0;
	u32 addnl_dvdr = 1;
	u32 coal_intvl = 0;

	if (!coal->rx_coalesce_usecs)
		return -EINVAL;

	coal_intvl = coal->rx_coalesce_usecs;

	int_ctrl =  readl(&priv->wr_regs->int_control);
	prescale = priv->bus_freq_mhz * 4;

	if (coal_intvl < CPSW_CMINTMIN_INTVL)
		coal_intvl = CPSW_CMINTMIN_INTVL;

	if (coal_intvl > CPSW_CMINTMAX_INTVL) {
		/* Interrupt pacer works with 4us Pulse, we can
		 * throttle further by dilating the 4us pulse.
		 */
		addnl_dvdr = CPSW_INTPRESCALE_MASK / prescale;

		if (addnl_dvdr > 1) {
			prescale *= addnl_dvdr;
			if (coal_intvl > (CPSW_CMINTMAX_INTVL * addnl_dvdr))
				coal_intvl = (CPSW_CMINTMAX_INTVL
						* addnl_dvdr);
		} else {
			addnl_dvdr = 1;
			coal_intvl = CPSW_CMINTMAX_INTVL;
		}
	}

	num_interrupts = (1000 * addnl_dvdr) / coal_intvl;
	writel(num_interrupts, &priv->wr_regs->rx_imax);
	writel(num_interrupts, &priv->wr_regs->tx_imax);

	int_ctrl |= CPSW_INTPACEEN;
	int_ctrl &= (~CPSW_INTPRESCALE_MASK);
	int_ctrl |= (prescale & CPSW_INTPRESCALE_MASK);
	writel(int_ctrl, &priv->wr_regs->int_control);

	cpsw_notice(priv, timer, "Set coalesce to %d usecs.\n", coal_intvl);
	if (priv->data.dual_emac) {
		int i;

		for (i = 0; i < priv->data.slaves; i++) {
			priv = netdev_priv(priv->slaves[i].ndev);
			priv->coal_intvl = coal_intvl;
		}
	} else {
		priv->coal_intvl = coal_intvl;
	}

	return 0;
}

static inline int __show_stat(char *buf, int maxlen, const char *name, u32 val)
{
	static char *leader = "........................................";
@@ -834,6 +927,14 @@ static int cpsw_ndo_open(struct net_device *ndev)
		cpsw_info(priv, ifup, "submitted %d rx descriptors\n", i);
	}

	/* Enable Interrupt pacing if configured */
	if (priv->coal_intvl != 0) {
		struct ethtool_coalesce coal;

		coal.rx_coalesce_usecs = (priv->coal_intvl << 4);
		cpsw_set_coalesce(ndev, &coal);
	}

	cpdma_ctlr_start(priv->dma);
	cpsw_intr_enable(priv);
	napi_enable(&priv->napi);
@@ -942,7 +1043,7 @@ static void cpsw_ndo_change_rx_flags(struct net_device *ndev, int flags)

static void cpsw_hwtstamp_v1(struct cpsw_priv *priv)
{
	struct cpsw_slave *slave = &priv->slaves[priv->data.cpts_active_slave];
	struct cpsw_slave *slave = &priv->slaves[priv->data.active_slave];
	u32 ts_en, seq_id;

	if (!priv->cpts->tx_enable && !priv->cpts->rx_enable) {
@@ -971,7 +1072,7 @@ static void cpsw_hwtstamp_v2(struct cpsw_priv *priv)
	if (priv->data.dual_emac)
		slave = &priv->slaves[priv->emac_port];
	else
		slave = &priv->slaves[priv->data.cpts_active_slave];
		slave = &priv->slaves[priv->data.active_slave];

	ctrl = slave_read(slave, CPSW2_CONTROL);
	ctrl &= ~CTRL_ALL_TS_MASK;
@@ -1056,16 +1157,28 @@ static int cpsw_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr)

static int cpsw_ndo_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
{
	struct cpsw_priv *priv = netdev_priv(dev);
	struct mii_ioctl_data *data = if_mii(req);
	int slave_no = cpsw_slave_index(priv);

	if (!netif_running(dev))
		return -EINVAL;

	switch (cmd) {
#ifdef CONFIG_TI_CPTS
	if (cmd == SIOCSHWTSTAMP)
	case SIOCSHWTSTAMP:
		return cpsw_hwtstamp_ioctl(dev, req);
#endif
	case SIOCGMIIPHY:
		data->phy_id = priv->slaves[slave_no].phy->addr;
		break;
	default:
		return -ENOTSUPP;
	}

	return 0;
}

static void cpsw_ndo_tx_timeout(struct net_device *ndev)
{
	struct cpsw_priv *priv = netdev_priv(ndev);
@@ -1244,12 +1357,39 @@ static int cpsw_get_ts_info(struct net_device *ndev,
	return 0;
}

static int cpsw_get_settings(struct net_device *ndev,
			     struct ethtool_cmd *ecmd)
{
	struct cpsw_priv *priv = netdev_priv(ndev);
	int slave_no = cpsw_slave_index(priv);

	if (priv->slaves[slave_no].phy)
		return phy_ethtool_gset(priv->slaves[slave_no].phy, ecmd);
	else
		return -EOPNOTSUPP;
}

static int cpsw_set_settings(struct net_device *ndev, struct ethtool_cmd *ecmd)
{
	struct cpsw_priv *priv = netdev_priv(ndev);
	int slave_no = cpsw_slave_index(priv);

	if (priv->slaves[slave_no].phy)
		return phy_ethtool_sset(priv->slaves[slave_no].phy, ecmd);
	else
		return -EOPNOTSUPP;
}

static const struct ethtool_ops cpsw_ethtool_ops = {
	.get_drvinfo	= cpsw_get_drvinfo,
	.get_msglevel	= cpsw_get_msglevel,
	.set_msglevel	= cpsw_set_msglevel,
	.get_link	= ethtool_op_get_link,
	.get_ts_info	= cpsw_get_ts_info,
	.get_settings	= cpsw_get_settings,
	.set_settings	= cpsw_set_settings,
	.get_coalesce	= cpsw_get_coalesce,
	.set_coalesce	= cpsw_set_coalesce,
};

static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv,
@@ -1282,12 +1422,12 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data,
	}
	data->slaves = prop;

	if (of_property_read_u32(node, "cpts_active_slave", &prop)) {
		pr_err("Missing cpts_active_slave property in the DT.\n");
	if (of_property_read_u32(node, "active_slave", &prop)) {
		pr_err("Missing active_slave property in the DT.\n");
		ret = -EINVAL;
		goto error_ret;
	}
	data->cpts_active_slave = prop;
	data->active_slave = prop;

	if (of_property_read_u32(node, "cpts_clock_mult", &prop)) {
		pr_err("Missing cpts_clock_mult property in the DT.\n");
@@ -1437,6 +1577,9 @@ static int cpsw_probe_dual_emac(struct platform_device *pdev,
	priv_sl2->slaves = priv->slaves;
	priv_sl2->clk = priv->clk;

	priv_sl2->coal_intvl = 0;
	priv_sl2->bus_freq_mhz = priv->bus_freq_mhz;

	priv_sl2->cpsw_res = priv->cpsw_res;
	priv_sl2->regs = priv->regs;
	priv_sl2->host_port = priv->host_port;
@@ -1546,6 +1689,8 @@ static int cpsw_probe(struct platform_device *pdev)
		ret = -ENODEV;
		goto clean_slave_ret;
	}
	priv->coal_intvl = 0;
	priv->bus_freq_mhz = clk_get_rate(priv->clk) / 1000000;

	priv->cpsw_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!priv->cpsw_res) {
+1 −1
Original line number Diff line number Diff line
@@ -30,7 +30,7 @@ struct cpsw_platform_data {
	u32	channels;	/* number of cpdma channels (symmetric) */
	u32	slaves;		/* number of slave cpgmac ports */
	struct cpsw_slave_data	*slave_data;
	u32	cpts_active_slave; /* time stamping slave */
	u32	active_slave; /* time stamping, ethtool and SIOCGMIIPHY slave */
	u32	cpts_clock_mult;  /* convert input clock ticks to nanoseconds */
	u32	cpts_clock_shift; /* convert input clock ticks to nanoseconds */
	u32	ale_entries;	/* ale table size */