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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
f251f4e37c
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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,38 +1039,44 @@ 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);
|
||||
netif_tx_lock_bh(ndev);
|
||||
fec_restart(ndev);
|
||||
netif_wake_queue(ndev);
|
||||
netif_tx_unlock_bh(ndev);
|
||||
napi_enable(&fep->napi);
|
||||
}
|
||||
rtnl_unlock();
|
||||
rtnl_lock();
|
||||
if (netif_device_present(ndev) || netif_running(ndev)) {
|
||||
napi_disable(&fep->napi);
|
||||
netif_tx_lock_bh(ndev);
|
||||
fec_restart(ndev);
|
||||
netif_wake_queue(ndev);
|
||||
netif_tx_unlock_bh(ndev);
|
||||
napi_enable(&fep->napi);
|
||||
}
|
||||
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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user