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

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

Merge branch 'fec-next'



Russell King says:

====================
Freescale ethernet driver updates (part 3)

Here's the third batch of patches for the Freescale FEC ethernet driver,
based upon the previous set of patches.  This concludes the changes I
currently have prepared and have been reviewed for the next merge window
at this time.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents efa95b01 bfd4ecdd
Loading
Loading
Loading
Loading
+2 −7
Original line number Diff line number Diff line
@@ -256,12 +256,6 @@ struct bufdesc_ex {
#define FLAG_RX_CSUM_ENABLED	(BD_ENET_RX_ICE | BD_ENET_RX_PCR)
#define FLAG_RX_CSUM_ERROR	(BD_ENET_RX_ICE | BD_ENET_RX_PCR)

struct fec_enet_delayed_work {
	struct delayed_work delay_work;
	bool timeout;
	bool trig_tx;
};

/* The FEC buffer descriptors track the ring buffers.  The rx_bd_base and
 * tx_bd_base always point to the base of the buffer descriptors.  The
 * cur_rx and cur_tx point to the currently available buffer.
@@ -327,6 +321,8 @@ struct fec_enet_private {
	struct	napi_struct napi;
	int	csum_flags;

	struct work_struct tx_timeout_work;

	struct ptp_clock *ptp_clock;
	struct ptp_clock_info ptp_caps;
	unsigned long last_overflow_check;
@@ -339,7 +335,6 @@ struct fec_enet_private {
	int hwts_rx_en;
	int hwts_tx_en;
	struct timer_list time_keep;
	struct fec_enet_delayed_work delay_work;
	struct regulator *reg_phy;
};

+66 −73
Original line number Diff line number Diff line
@@ -320,6 +320,27 @@ static void *swap_buffer(void *bufaddr, int len)
	return bufaddr;
}

static void fec_dump(struct net_device *ndev)
{
	struct fec_enet_private *fep = netdev_priv(ndev);
	struct bufdesc *bdp = fep->tx_bd_base;
	unsigned int index = 0;

	netdev_info(ndev, "TX ring dump\n");
	pr_info("Nr     SC     addr       len  SKB\n");

	do {
		pr_info("%3u %c%c 0x%04x 0x%08lx %4u %p\n",
			index,
			bdp == fep->cur_tx ? 'S' : ' ',
			bdp == fep->dirty_tx ? 'H' : ' ',
			bdp->cbd_sc, bdp->cbd_bufaddr, bdp->cbd_datlen,
			fep->tx_skbuff[index]);
		bdp = fec_enet_get_nextdesc(bdp, fep);
		index++;
	} while (bdp != fep->tx_bd_base);
}

static inline bool is_ipv4_pkt(struct sk_buff *skb)
{
	return skb->protocol == htons(ETH_P_IP) && ip_hdr(skb)->version == 4;
@@ -342,22 +363,6 @@ fec_enet_clear_csum(struct sk_buff *skb, struct net_device *ndev)
	return 0;
}

static void
fec_enet_submit_work(struct bufdesc *bdp, struct fec_enet_private *fep)
{
	const struct platform_device_id *id_entry =
				platform_get_device_id(fep->pdev);
	struct bufdesc *bdp_pre;

	bdp_pre = fec_enet_get_prevdesc(bdp, fep);
	if ((id_entry->driver_data & FEC_QUIRK_ERR006358) &&
	    !(bdp_pre->cbd_sc & BD_ENET_TX_READY)) {
		fep->delay_work.trig_tx = true;
		schedule_delayed_work(&(fep->delay_work.delay_work),
					msecs_to_jiffies(1));
	}
}

static int
fec_enet_txq_submit_frag_skb(struct sk_buff *skb, struct net_device *ndev)
{
@@ -545,8 +550,6 @@ static int fec_enet_txq_submit_skb(struct sk_buff *skb, struct net_device *ndev)
	status |= (BD_ENET_TX_READY | BD_ENET_TX_TC);
	bdp->cbd_sc = status;

	fec_enet_submit_work(bdp, fep);

	/* If this was the last BD in the ring, start at the beginning again. */
	bdp = fec_enet_get_nextdesc(last_bdp, fep);

@@ -735,8 +738,6 @@ static int fec_enet_txq_submit_tso(struct sk_buff *skb, struct net_device *ndev)
	/* Save skb pointer */
	fep->tx_skbuff[index] = skb;

	fec_enet_submit_work(bdp, fep);

	skb_tx_timestamp(skb);
	fep->cur_tx = bdp;

@@ -1038,22 +1039,19 @@ fec_timeout(struct net_device *ndev)
{
	struct fec_enet_private *fep = netdev_priv(ndev);

	fec_dump(ndev);

	ndev->stats.tx_errors++;

	fep->delay_work.timeout = true;
	schedule_delayed_work(&(fep->delay_work.delay_work), 0);
	schedule_work(&fep->tx_timeout_work);
}

static void fec_enet_work(struct work_struct *work)
static void fec_enet_timeout_work(struct work_struct *work)
{
	struct fec_enet_private *fep =
		container_of(work,
			     struct fec_enet_private,
			     delay_work.delay_work.work);
		container_of(work, struct fec_enet_private, tx_timeout_work);
	struct net_device *ndev = fep->netdev;

	if (fep->delay_work.timeout) {
		fep->delay_work.timeout = false;
	rtnl_lock();
	if (netif_device_present(ndev) || netif_running(ndev)) {
		napi_disable(&fep->napi);
@@ -1066,10 +1064,19 @@ static void fec_enet_work(struct work_struct *work)
	rtnl_unlock();
}

	if (fep->delay_work.trig_tx) {
		fep->delay_work.trig_tx = false;
		writel(0, fep->hwp + FEC_X_DES_ACTIVE);
	}
static void
fec_enet_hwtstamp(struct fec_enet_private *fep, unsigned ts,
	struct skb_shared_hwtstamps *hwtstamps)
{
	unsigned long flags;
	u64 ns;

	spin_lock_irqsave(&fep->tmreg_lock, flags);
	ns = timecounter_cyc2time(&fep->tc, ts);
	spin_unlock_irqrestore(&fep->tmreg_lock, flags);

	memset(hwtstamps, 0, sizeof(*hwtstamps));
	hwtstamps->hwtstamp = ns_to_ktime(ns);
}

static void
@@ -1130,20 +1137,12 @@ fec_enet_tx(struct net_device *ndev)
		if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS) &&
			fep->bufdesc_ex) {
			struct skb_shared_hwtstamps shhwtstamps;
			unsigned long flags;
			struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;

			memset(&shhwtstamps, 0, sizeof(shhwtstamps));
			spin_lock_irqsave(&fep->tmreg_lock, flags);
			shhwtstamps.hwtstamp = ns_to_ktime(
				timecounter_cyc2time(&fep->tc, ebdp->ts));
			spin_unlock_irqrestore(&fep->tmreg_lock, flags);
			fec_enet_hwtstamp(fep, ebdp->ts, &shhwtstamps);
			skb_tstamp_tx(skb, &shhwtstamps);
		}

		if (status & BD_ENET_TX_READY)
			netdev_err(ndev, "HEY! Enet xmit interrupt and TX_READY\n");

		/* Deferred means some collisions occurred during transmit,
		 * but we eventually sent the packet OK.
		 */
@@ -1166,7 +1165,10 @@ fec_enet_tx(struct net_device *ndev)
				netif_wake_queue(ndev);
		}
	}
	return;

	/* ERR006538: Keep the transmitter going */
	if (bdp != fep->cur_tx && readl(fep->hwp + FEC_X_DES_ACTIVE) == 0)
		writel(0, fep->hwp + FEC_X_DES_ACTIVE);
}

/* During a receive, the cur_rx points to the current incoming buffer.
@@ -1212,6 +1214,8 @@ fec_enet_rx(struct net_device *ndev, int budget)
		if ((status & BD_ENET_RX_LAST) == 0)
			netdev_err(ndev, "rcv is not +last\n");

		writel(FEC_ENET_RXF, fep->hwp + FEC_IEVENT);

		/* Check for errors. */
		if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
			   BD_ENET_RX_CR | BD_ENET_RX_OV)) {
@@ -1294,18 +1298,9 @@ fec_enet_rx(struct net_device *ndev, int budget)
			skb->protocol = eth_type_trans(skb, ndev);

			/* Get receive timestamp from the skb */
			if (fep->hwts_rx_en && fep->bufdesc_ex) {
				struct skb_shared_hwtstamps *shhwtstamps =
							    skb_hwtstamps(skb);
				unsigned long flags;

				memset(shhwtstamps, 0, sizeof(*shhwtstamps));

				spin_lock_irqsave(&fep->tmreg_lock, flags);
				shhwtstamps->hwtstamp = ns_to_ktime(
				    timecounter_cyc2time(&fep->tc, ebdp->ts));
				spin_unlock_irqrestore(&fep->tmreg_lock, flags);
			}
			if (fep->hwts_rx_en && fep->bufdesc_ex)
				fec_enet_hwtstamp(fep, ebdp->ts,
						  skb_hwtstamps(skb));

			if (fep->bufdesc_ex &&
			    (fep->csum_flags & FLAG_RX_CSUM_ENABLED)) {
@@ -2040,21 +2035,19 @@ static int fec_enet_nway_reset(struct net_device *dev)
}

static const struct ethtool_ops fec_enet_ethtool_ops = {
#if !defined(CONFIG_M5272)
	.get_pauseparam		= fec_enet_get_pauseparam,
	.set_pauseparam		= fec_enet_set_pauseparam,
#endif
	.get_settings		= fec_enet_get_settings,
	.set_settings		= fec_enet_set_settings,
	.get_drvinfo		= fec_enet_get_drvinfo,
	.get_link		= ethtool_op_get_link,
	.get_ts_info		= fec_enet_get_ts_info,
	.nway_reset		= fec_enet_nway_reset,
	.get_link		= ethtool_op_get_link,
#ifndef CONFIG_M5272
	.get_ethtool_stats	= fec_enet_get_ethtool_stats,
	.get_pauseparam		= fec_enet_get_pauseparam,
	.set_pauseparam		= fec_enet_set_pauseparam,
	.get_strings		= fec_enet_get_strings,
	.get_ethtool_stats	= fec_enet_get_ethtool_stats,
	.get_sset_count		= fec_enet_get_sset_count,
#endif
	.get_ts_info		= fec_enet_get_ts_info,
};

static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
@@ -2664,7 +2657,7 @@ fec_probe(struct platform_device *pdev)
	if (fep->bufdesc_ex && fep->ptp_clock)
		netdev_info(ndev, "registered PHC device %d\n", fep->dev_id);

	INIT_DELAYED_WORK(&(fep->delay_work.delay_work), fec_enet_work);
	INIT_WORK(&fep->tx_timeout_work, fec_enet_timeout_work);
	return 0;

failed_register:
@@ -2689,7 +2682,7 @@ fec_drv_remove(struct platform_device *pdev)
	struct net_device *ndev = platform_get_drvdata(pdev);
	struct fec_enet_private *fep = netdev_priv(ndev);

	cancel_delayed_work_sync(&(fep->delay_work.delay_work));
	cancel_work_sync(&fep->tx_timeout_work);
	unregister_netdev(ndev);
	fec_enet_mii_remove(fep);
	del_timer_sync(&fep->time_keep);