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

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
...@@ -256,12 +256,6 @@ struct bufdesc_ex { ...@@ -256,12 +256,6 @@ struct bufdesc_ex {
#define FLAG_RX_CSUM_ENABLED (BD_ENET_RX_ICE | BD_ENET_RX_PCR) #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) #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 /* 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 * tx_bd_base always point to the base of the buffer descriptors. The
* cur_rx and cur_tx point to the currently available buffer. * cur_rx and cur_tx point to the currently available buffer.
...@@ -327,6 +321,8 @@ struct fec_enet_private { ...@@ -327,6 +321,8 @@ struct fec_enet_private {
struct napi_struct napi; struct napi_struct napi;
int csum_flags; int csum_flags;
struct work_struct tx_timeout_work;
struct ptp_clock *ptp_clock; struct ptp_clock *ptp_clock;
struct ptp_clock_info ptp_caps; struct ptp_clock_info ptp_caps;
unsigned long last_overflow_check; unsigned long last_overflow_check;
...@@ -339,7 +335,6 @@ struct fec_enet_private { ...@@ -339,7 +335,6 @@ struct fec_enet_private {
int hwts_rx_en; int hwts_rx_en;
int hwts_tx_en; int hwts_tx_en;
struct timer_list time_keep; struct timer_list time_keep;
struct fec_enet_delayed_work delay_work;
struct regulator *reg_phy; struct regulator *reg_phy;
}; };
......
...@@ -320,6 +320,27 @@ static void *swap_buffer(void *bufaddr, int len) ...@@ -320,6 +320,27 @@ static void *swap_buffer(void *bufaddr, int len)
return bufaddr; 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) static inline bool is_ipv4_pkt(struct sk_buff *skb)
{ {
return skb->protocol == htons(ETH_P_IP) && ip_hdr(skb)->version == 4; 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) ...@@ -342,22 +363,6 @@ fec_enet_clear_csum(struct sk_buff *skb, struct net_device *ndev)
return 0; 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 static int
fec_enet_txq_submit_frag_skb(struct sk_buff *skb, struct net_device *ndev) 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) ...@@ -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); status |= (BD_ENET_TX_READY | BD_ENET_TX_TC);
bdp->cbd_sc = status; bdp->cbd_sc = status;
fec_enet_submit_work(bdp, fep);
/* If this was the last BD in the ring, start at the beginning again. */ /* If this was the last BD in the ring, start at the beginning again. */
bdp = fec_enet_get_nextdesc(last_bdp, fep); 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) ...@@ -735,8 +738,6 @@ static int fec_enet_txq_submit_tso(struct sk_buff *skb, struct net_device *ndev)
/* Save skb pointer */ /* Save skb pointer */
fep->tx_skbuff[index] = skb; fep->tx_skbuff[index] = skb;
fec_enet_submit_work(bdp, fep);
skb_tx_timestamp(skb); skb_tx_timestamp(skb);
fep->cur_tx = bdp; fep->cur_tx = bdp;
...@@ -1038,38 +1039,44 @@ fec_timeout(struct net_device *ndev) ...@@ -1038,38 +1039,44 @@ fec_timeout(struct net_device *ndev)
{ {
struct fec_enet_private *fep = netdev_priv(ndev); struct fec_enet_private *fep = netdev_priv(ndev);
fec_dump(ndev);
ndev->stats.tx_errors++; ndev->stats.tx_errors++;
fep->delay_work.timeout = true; schedule_work(&fep->tx_timeout_work);
schedule_delayed_work(&(fep->delay_work.delay_work), 0);
} }
static void fec_enet_work(struct work_struct *work) static void fec_enet_timeout_work(struct work_struct *work)
{ {
struct fec_enet_private *fep = struct fec_enet_private *fep =
container_of(work, container_of(work, struct fec_enet_private, tx_timeout_work);
struct fec_enet_private,
delay_work.delay_work.work);
struct net_device *ndev = fep->netdev; struct net_device *ndev = fep->netdev;
if (fep->delay_work.timeout) { rtnl_lock();
fep->delay_work.timeout = false; if (netif_device_present(ndev) || netif_running(ndev)) {
rtnl_lock(); napi_disable(&fep->napi);
if (netif_device_present(ndev) || netif_running(ndev)) { netif_tx_lock_bh(ndev);
napi_disable(&fep->napi); fec_restart(ndev);
netif_tx_lock_bh(ndev); netif_wake_queue(ndev);
fec_restart(ndev); netif_tx_unlock_bh(ndev);
netif_wake_queue(ndev); napi_enable(&fep->napi);
netif_tx_unlock_bh(ndev);
napi_enable(&fep->napi);
}
rtnl_unlock();
} }
rtnl_unlock();
}
if (fep->delay_work.trig_tx) { static void
fep->delay_work.trig_tx = false; fec_enet_hwtstamp(struct fec_enet_private *fep, unsigned ts,
writel(0, fep->hwp + FEC_X_DES_ACTIVE); 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 static void
...@@ -1130,20 +1137,12 @@ fec_enet_tx(struct net_device *ndev) ...@@ -1130,20 +1137,12 @@ fec_enet_tx(struct net_device *ndev)
if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS) && if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS) &&
fep->bufdesc_ex) { fep->bufdesc_ex) {
struct skb_shared_hwtstamps shhwtstamps; struct skb_shared_hwtstamps shhwtstamps;
unsigned long flags;
struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp; struct bufdesc_ex *ebdp = (struct bufdesc_ex *)bdp;
memset(&shhwtstamps, 0, sizeof(shhwtstamps)); fec_enet_hwtstamp(fep, ebdp->ts, &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);
skb_tstamp_tx(skb, &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, /* Deferred means some collisions occurred during transmit,
* but we eventually sent the packet OK. * but we eventually sent the packet OK.
*/ */
...@@ -1166,7 +1165,10 @@ fec_enet_tx(struct net_device *ndev) ...@@ -1166,7 +1165,10 @@ fec_enet_tx(struct net_device *ndev)
netif_wake_queue(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. /* 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) ...@@ -1212,6 +1214,8 @@ fec_enet_rx(struct net_device *ndev, int budget)
if ((status & BD_ENET_RX_LAST) == 0) if ((status & BD_ENET_RX_LAST) == 0)
netdev_err(ndev, "rcv is not +last\n"); netdev_err(ndev, "rcv is not +last\n");
writel(FEC_ENET_RXF, fep->hwp + FEC_IEVENT);
/* Check for errors. */ /* Check for errors. */
if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO | if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
BD_ENET_RX_CR | BD_ENET_RX_OV)) { BD_ENET_RX_CR | BD_ENET_RX_OV)) {
...@@ -1294,18 +1298,9 @@ fec_enet_rx(struct net_device *ndev, int budget) ...@@ -1294,18 +1298,9 @@ fec_enet_rx(struct net_device *ndev, int budget)
skb->protocol = eth_type_trans(skb, ndev); skb->protocol = eth_type_trans(skb, ndev);
/* Get receive timestamp from the skb */ /* Get receive timestamp from the skb */
if (fep->hwts_rx_en && fep->bufdesc_ex) { if (fep->hwts_rx_en && fep->bufdesc_ex)
struct skb_shared_hwtstamps *shhwtstamps = fec_enet_hwtstamp(fep, ebdp->ts,
skb_hwtstamps(skb); 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->bufdesc_ex && if (fep->bufdesc_ex &&
(fep->csum_flags & FLAG_RX_CSUM_ENABLED)) { (fep->csum_flags & FLAG_RX_CSUM_ENABLED)) {
...@@ -2040,21 +2035,19 @@ static int fec_enet_nway_reset(struct net_device *dev) ...@@ -2040,21 +2035,19 @@ static int fec_enet_nway_reset(struct net_device *dev)
} }
static const struct ethtool_ops fec_enet_ethtool_ops = { 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, .get_settings = fec_enet_get_settings,
.set_settings = fec_enet_set_settings, .set_settings = fec_enet_set_settings,
.get_drvinfo = fec_enet_get_drvinfo, .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, .nway_reset = fec_enet_nway_reset,
.get_link = ethtool_op_get_link,
#ifndef CONFIG_M5272 #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_strings = fec_enet_get_strings,
.get_ethtool_stats = fec_enet_get_ethtool_stats,
.get_sset_count = fec_enet_get_sset_count, .get_sset_count = fec_enet_get_sset_count,
#endif #endif
.get_ts_info = fec_enet_get_ts_info,
}; };
static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
...@@ -2664,7 +2657,7 @@ fec_probe(struct platform_device *pdev) ...@@ -2664,7 +2657,7 @@ fec_probe(struct platform_device *pdev)
if (fep->bufdesc_ex && fep->ptp_clock) if (fep->bufdesc_ex && fep->ptp_clock)
netdev_info(ndev, "registered PHC device %d\n", fep->dev_id); 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; return 0;
failed_register: failed_register:
...@@ -2689,7 +2682,7 @@ fec_drv_remove(struct platform_device *pdev) ...@@ -2689,7 +2682,7 @@ fec_drv_remove(struct platform_device *pdev)
struct net_device *ndev = platform_get_drvdata(pdev); struct net_device *ndev = platform_get_drvdata(pdev);
struct fec_enet_private *fep = netdev_priv(ndev); 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); unregister_netdev(ndev);
fec_enet_mii_remove(fep); fec_enet_mii_remove(fep);
del_timer_sync(&fep->time_keep); del_timer_sync(&fep->time_keep);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment