Loading drivers/net/ethernet/msm/emac/emac.h +29 −0 Original line number Diff line number Diff line Loading @@ -591,6 +591,28 @@ struct emac_tpd_ring { u32 last_produce_idx; }; #define EMAC_HWTXTSTAMP_FIFO_DEPTH 8 #define EMAC_TX_POLL_HWTXTSTAMP_THRESHOLD EMAC_HWTXTSTAMP_FIFO_DEPTH /* HW tx timestamp */ struct emac_hwtxtstamp { u32 ts_idx; u32 sec; u32 ns; }; struct emac_tx_tstamp_stats { u32 tx; u32 rx; u32 deliver; u32 drop; u32 lost; u32 timeout; u32 sched; u32 poll; u32 tx_poll; }; /* tx queue */ struct emac_tx_queue { struct device *dev; /* device for dma mapping */ Loading Loading @@ -639,6 +661,13 @@ struct emac_adapter { struct emac_hw hw; struct emac_hw_stats hw_stats; /* tx timestamping queue */ struct sk_buff_head hwtxtstamp_pending_queue; struct sk_buff_head hwtxtstamp_ready_queue; struct work_struct hwtxtstamp_task; spinlock_t hwtxtstamp_lock; /* lock for hwtxtstamp */ struct emac_tx_tstamp_stats hwtxtstamp_stats; struct work_struct emac_task; struct timer_list emac_timer; unsigned long link_jiffies; Loading drivers/net/ethernet/msm/emac/emac_hw.c +17 −0 Original line number Diff line number Diff line Loading @@ -1496,3 +1496,20 @@ void emac_hw_set_mac_addr(struct emac_hw *hw, u8 *addr) emac_reg_w32(hw, EMAC, EMAC_MAC_STA_ADDR1, sta); wmb(); } /* Read one entry from the HW tx timestamp FIFO */ bool emac_hw_read_tx_tstamp(struct emac_hw *hw, struct emac_hwtxtstamp *ts) { u32 ts_idx; ts_idx = emac_reg_r32(hw, EMAC_CSR, EMAC_EMAC_WRAPPER_TX_TS_INX); if (ts_idx & EMAC_WRAPPER_TX_TS_EMPTY) return false; ts->ns = emac_reg_r32(hw, EMAC_CSR, EMAC_EMAC_WRAPPER_TX_TS_LO); ts->sec = emac_reg_r32(hw, EMAC_CSR, EMAC_EMAC_WRAPPER_TX_TS_HI); ts->ts_idx = ts_idx & EMAC_WRAPPER_TX_TS_INX_BMSK; return true; } drivers/net/ethernet/msm/emac/emac_hw.h +4 −0 Original line number Diff line number Diff line Loading @@ -72,6 +72,10 @@ extern void emac_hw_stop_mac(struct emac_hw *hw); extern void emac_hw_set_mac_addr(struct emac_hw *hw, u8 *addr); /* TX Timestamp */ extern bool emac_hw_read_tx_tstamp(struct emac_hw *hw, struct emac_hwtxtstamp *ts); #define IMR_NORMAL_MASK (\ ISR_ERROR |\ ISR_GPHY_LINK |\ Loading drivers/net/ethernet/msm/emac/emac_main.c +155 −29 Original line number Diff line number Diff line Loading @@ -52,6 +52,20 @@ const char emac_drv_version[] = DRV_VERSION; #define EMAC_RSS_IDT_SIZE 256 #define EMAC_SKB_CB(skb) ((struct emac_skb_cb *)(skb)->cb) struct emac_skb_cb { u32 tpd_idx; unsigned long jiffies; }; #define EMAC_HWTXTSTAMP_CB(skb) ((struct emac_hwtxtstamp_cb *)(skb)->cb) struct emac_hwtxtstamp_cb { u32 sec; u32 ns; }; static int msm_emac_msglvl = -1; module_param_named(msglvl, msm_emac_msglvl, int, S_IRUGO | S_IWUSR | S_IWGRP); Loading Loading @@ -444,42 +458,122 @@ static void emac_clean_rfdesc(struct emac_rx_queue *rxque, rxque->rfd.process_idx = consume_idx; } static void emac_read_tx_tstamp_fifo(struct emac_hw *hw, struct emac_tx_queue *txque) static inline bool emac_skb_cb_expired(struct sk_buff *skb) { struct emac_buffer *tpbuf; u32 ts_idx = 0; u32 sec, ns; if (time_is_after_jiffies(EMAC_SKB_CB(skb)->jiffies + msecs_to_jiffies(100))) return false; return true; } while (1) { ts_idx = emac_reg_r32(hw, EMAC_CSR, EMAC_EMAC_WRAPPER_TX_TS_INX); if (ts_idx & EMAC_WRAPPER_TX_TS_EMPTY) /* proper lock must be acquired before polling */ static void emac_poll_hwtxtstamp(struct emac_adapter *adpt) { struct sk_buff_head *pending_q = &adpt->hwtxtstamp_pending_queue; struct sk_buff_head *q = &adpt->hwtxtstamp_ready_queue; struct sk_buff *skb, *skb_tmp; struct emac_hwtxtstamp hwtxtstamp; while (emac_hw_read_tx_tstamp(&adpt->hw, &hwtxtstamp)) { bool found = false; adpt->hwtxtstamp_stats.rx++; skb_queue_walk_safe(pending_q, skb, skb_tmp) { if (EMAC_SKB_CB(skb)->tpd_idx == hwtxtstamp.ts_idx) { struct sk_buff *pskb; EMAC_HWTXTSTAMP_CB(skb)->sec = hwtxtstamp.sec; EMAC_HWTXTSTAMP_CB(skb)->ns = hwtxtstamp.ns; /* the tx timestamps for all the pending packets before this one are lost */ while ((pskb = __skb_dequeue(pending_q)) != skb) { EMAC_HWTXTSTAMP_CB(pskb)->sec = 0; EMAC_HWTXTSTAMP_CB(pskb)->ns = 0; __skb_queue_tail(q, pskb); adpt->hwtxtstamp_stats.lost++; } __skb_queue_tail(q, skb); found = true; break; } } ns = emac_reg_r32(hw, EMAC_CSR, EMAC_EMAC_WRAPPER_TX_TS_LO); sec = emac_reg_r32(hw, EMAC_CSR, EMAC_EMAC_WRAPPER_TX_TS_HI); if (!found) { emac_dbg(adpt, tx_done, "no entry(tpd=%d) found, drop tx timestamp\n", hwtxtstamp.ts_idx); adpt->hwtxtstamp_stats.drop++; } } ts_idx &= EMAC_WRAPPER_TX_TS_INX_BMSK; if ((ts_idx < txque->tpd.consume_idx) || (ts_idx > txque->tpd.last_produce_idx)) { emac_warn(hw->adpt, tx_done, "zombie timestamp desc idx %d\n", ts_idx); continue; skb_queue_walk_safe(pending_q, skb, skb_tmp) { /* No packet after this one expires */ if (!emac_skb_cb_expired(skb)) break; adpt->hwtxtstamp_stats.timeout++; emac_dbg(adpt, tx_done, "tx timestamp timeout: tpd_idx=%d\n", EMAC_SKB_CB(skb)->tpd_idx); __skb_unlink(skb, pending_q); EMAC_HWTXTSTAMP_CB(skb)->sec = 0; EMAC_HWTXTSTAMP_CB(skb)->ns = 0; __skb_queue_tail(q, skb); } } tpbuf = GET_TPD_BUFFER(txque, ts_idx); static void emac_schedule_hwtxtstamp_task(struct emac_adapter *adpt) { if (CHK_ADPT_FLAG(STATE_DOWN)) return; if (schedule_work(&adpt->hwtxtstamp_task)) adpt->hwtxtstamp_stats.sched++; } static void emac_hwtxtstamp_task_routine(struct work_struct *work) { struct emac_adapter *adpt = container_of(work, struct emac_adapter, hwtxtstamp_task); struct sk_buff *skb; struct sk_buff_head q; unsigned long flags; adpt->hwtxtstamp_stats.poll++; __skb_queue_head_init(&q); while (1) { spin_lock_irqsave(&adpt->hwtxtstamp_lock, flags); if (adpt->hwtxtstamp_pending_queue.qlen) emac_poll_hwtxtstamp(adpt); skb_queue_splice_tail_init(&adpt->hwtxtstamp_ready_queue, &q); spin_unlock_irqrestore(&adpt->hwtxtstamp_lock, flags); if (tpbuf->skb && (skb_shinfo(tpbuf->skb)->tx_flags & SKBTX_HW_TSTAMP)) { if (!q.qlen) break; while ((skb = __skb_dequeue(&q))) { struct emac_hwtxtstamp_cb *cb = EMAC_HWTXTSTAMP_CB(skb); if (cb->sec || cb->ns) { struct skb_shared_hwtstamps ts; ts.hwtstamp = ktime_set(sec, ns); ts.syststamp = ktime_add_ns(ts.hwtstamp, hw->tstamp_tx_offset); skb_tstamp_tx(tpbuf->skb, &ts); ts.hwtstamp = ktime_set(cb->sec, cb->ns); ts.syststamp = ktime_add_ns( ts.hwtstamp, adpt->hw.tstamp_tx_offset); skb_tstamp_tx(skb, &ts); adpt->hwtxtstamp_stats.deliver++; } dev_kfree_skb_any(skb); } } if (adpt->hwtxtstamp_pending_queue.qlen) emac_schedule_hwtxtstamp_task(adpt); } /* Process receive event */ Loading Loading @@ -600,7 +694,6 @@ static void emac_handle_tx(struct emac_adapter *adpt, txque->que_idx, hw_consume_idx); while (txque->tpd.consume_idx != hw_consume_idx) { emac_read_tx_tstamp_fifo(hw, txque); tpbuf = GET_TPD_BUFFER(txque, txque->tpd.consume_idx); if (tpbuf->dma) { dma_unmap_single(txque->dev, tpbuf->dma, tpbuf->length, Loading Loading @@ -822,8 +915,29 @@ static void emac_tx_map(struct emac_adapter *adpt, if (CHK_HW_FLAG(TS_TX_EN) && (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) { struct sk_buff *skb_ts = skb_clone(skb, GFP_ATOMIC); if (likely(skb_ts)) { unsigned long flags; emac_set_tpdesc_tstamp_sav(txque); skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; skb_ts->sk = skb->sk; EMAC_SKB_CB(skb_ts)->tpd_idx = txque->tpd.last_produce_idx; EMAC_SKB_CB(skb_ts)->jiffies = get_jiffies_64(); skb_shinfo(skb_ts)->tx_flags |= SKBTX_IN_PROGRESS; spin_lock_irqsave(&adpt->hwtxtstamp_lock, flags); if (adpt->hwtxtstamp_pending_queue.qlen >= EMAC_TX_POLL_HWTXTSTAMP_THRESHOLD) { emac_poll_hwtxtstamp(adpt); adpt->hwtxtstamp_stats.tx_poll++; } __skb_queue_tail(&adpt->hwtxtstamp_pending_queue, skb_ts); spin_unlock_irqrestore(&adpt->hwtxtstamp_lock, flags); adpt->hwtxtstamp_stats.tx++; emac_schedule_hwtxtstamp_task(adpt); } } /* The last buffer info contain the skb address, Loading Loading @@ -1559,6 +1673,7 @@ void emac_down(struct emac_adapter *adpt, u32 ctrl) { struct net_device *netdev = adpt->netdev; struct emac_hw *hw = &adpt->hw; unsigned long flags; int i; SET_ADPT_FLAG(STATE_DOWN); Loading @@ -1581,6 +1696,12 @@ void emac_down(struct emac_adapter *adpt, u32 ctrl) CLI_ADPT_FLAG(TASK_CHK_SGMII_REQ); del_timer_sync(&adpt->emac_timer); cancel_work_sync(&adpt->hwtxtstamp_task); spin_lock_irqsave(&adpt->hwtxtstamp_lock, flags); __skb_queue_purge(&adpt->hwtxtstamp_pending_queue); __skb_queue_purge(&adpt->hwtxtstamp_ready_queue); spin_unlock_irqrestore(&adpt->hwtxtstamp_lock, flags); if (ctrl & EMAC_HW_CTRL_RESET_MAC) emac_hw_reset_mac(hw); Loading Loading @@ -2693,6 +2814,11 @@ static int emac_probe(struct platform_device *pdev) netif_napi_add(netdev, &adpt->rx_queue[i].napi, emac_napi_rtx, 64); spin_lock_init(&adpt->hwtxtstamp_lock); skb_queue_head_init(&adpt->hwtxtstamp_pending_queue); skb_queue_head_init(&adpt->hwtxtstamp_ready_queue); INIT_WORK(&adpt->hwtxtstamp_task, emac_hwtxtstamp_task_routine); SET_HW_FLAG(VLANSTRIP_EN); SET_ADPT_FLAG(STATE_DOWN); strlcpy(netdev->name, "eth%d", sizeof(netdev->name)); Loading Loading
drivers/net/ethernet/msm/emac/emac.h +29 −0 Original line number Diff line number Diff line Loading @@ -591,6 +591,28 @@ struct emac_tpd_ring { u32 last_produce_idx; }; #define EMAC_HWTXTSTAMP_FIFO_DEPTH 8 #define EMAC_TX_POLL_HWTXTSTAMP_THRESHOLD EMAC_HWTXTSTAMP_FIFO_DEPTH /* HW tx timestamp */ struct emac_hwtxtstamp { u32 ts_idx; u32 sec; u32 ns; }; struct emac_tx_tstamp_stats { u32 tx; u32 rx; u32 deliver; u32 drop; u32 lost; u32 timeout; u32 sched; u32 poll; u32 tx_poll; }; /* tx queue */ struct emac_tx_queue { struct device *dev; /* device for dma mapping */ Loading Loading @@ -639,6 +661,13 @@ struct emac_adapter { struct emac_hw hw; struct emac_hw_stats hw_stats; /* tx timestamping queue */ struct sk_buff_head hwtxtstamp_pending_queue; struct sk_buff_head hwtxtstamp_ready_queue; struct work_struct hwtxtstamp_task; spinlock_t hwtxtstamp_lock; /* lock for hwtxtstamp */ struct emac_tx_tstamp_stats hwtxtstamp_stats; struct work_struct emac_task; struct timer_list emac_timer; unsigned long link_jiffies; Loading
drivers/net/ethernet/msm/emac/emac_hw.c +17 −0 Original line number Diff line number Diff line Loading @@ -1496,3 +1496,20 @@ void emac_hw_set_mac_addr(struct emac_hw *hw, u8 *addr) emac_reg_w32(hw, EMAC, EMAC_MAC_STA_ADDR1, sta); wmb(); } /* Read one entry from the HW tx timestamp FIFO */ bool emac_hw_read_tx_tstamp(struct emac_hw *hw, struct emac_hwtxtstamp *ts) { u32 ts_idx; ts_idx = emac_reg_r32(hw, EMAC_CSR, EMAC_EMAC_WRAPPER_TX_TS_INX); if (ts_idx & EMAC_WRAPPER_TX_TS_EMPTY) return false; ts->ns = emac_reg_r32(hw, EMAC_CSR, EMAC_EMAC_WRAPPER_TX_TS_LO); ts->sec = emac_reg_r32(hw, EMAC_CSR, EMAC_EMAC_WRAPPER_TX_TS_HI); ts->ts_idx = ts_idx & EMAC_WRAPPER_TX_TS_INX_BMSK; return true; }
drivers/net/ethernet/msm/emac/emac_hw.h +4 −0 Original line number Diff line number Diff line Loading @@ -72,6 +72,10 @@ extern void emac_hw_stop_mac(struct emac_hw *hw); extern void emac_hw_set_mac_addr(struct emac_hw *hw, u8 *addr); /* TX Timestamp */ extern bool emac_hw_read_tx_tstamp(struct emac_hw *hw, struct emac_hwtxtstamp *ts); #define IMR_NORMAL_MASK (\ ISR_ERROR |\ ISR_GPHY_LINK |\ Loading
drivers/net/ethernet/msm/emac/emac_main.c +155 −29 Original line number Diff line number Diff line Loading @@ -52,6 +52,20 @@ const char emac_drv_version[] = DRV_VERSION; #define EMAC_RSS_IDT_SIZE 256 #define EMAC_SKB_CB(skb) ((struct emac_skb_cb *)(skb)->cb) struct emac_skb_cb { u32 tpd_idx; unsigned long jiffies; }; #define EMAC_HWTXTSTAMP_CB(skb) ((struct emac_hwtxtstamp_cb *)(skb)->cb) struct emac_hwtxtstamp_cb { u32 sec; u32 ns; }; static int msm_emac_msglvl = -1; module_param_named(msglvl, msm_emac_msglvl, int, S_IRUGO | S_IWUSR | S_IWGRP); Loading Loading @@ -444,42 +458,122 @@ static void emac_clean_rfdesc(struct emac_rx_queue *rxque, rxque->rfd.process_idx = consume_idx; } static void emac_read_tx_tstamp_fifo(struct emac_hw *hw, struct emac_tx_queue *txque) static inline bool emac_skb_cb_expired(struct sk_buff *skb) { struct emac_buffer *tpbuf; u32 ts_idx = 0; u32 sec, ns; if (time_is_after_jiffies(EMAC_SKB_CB(skb)->jiffies + msecs_to_jiffies(100))) return false; return true; } while (1) { ts_idx = emac_reg_r32(hw, EMAC_CSR, EMAC_EMAC_WRAPPER_TX_TS_INX); if (ts_idx & EMAC_WRAPPER_TX_TS_EMPTY) /* proper lock must be acquired before polling */ static void emac_poll_hwtxtstamp(struct emac_adapter *adpt) { struct sk_buff_head *pending_q = &adpt->hwtxtstamp_pending_queue; struct sk_buff_head *q = &adpt->hwtxtstamp_ready_queue; struct sk_buff *skb, *skb_tmp; struct emac_hwtxtstamp hwtxtstamp; while (emac_hw_read_tx_tstamp(&adpt->hw, &hwtxtstamp)) { bool found = false; adpt->hwtxtstamp_stats.rx++; skb_queue_walk_safe(pending_q, skb, skb_tmp) { if (EMAC_SKB_CB(skb)->tpd_idx == hwtxtstamp.ts_idx) { struct sk_buff *pskb; EMAC_HWTXTSTAMP_CB(skb)->sec = hwtxtstamp.sec; EMAC_HWTXTSTAMP_CB(skb)->ns = hwtxtstamp.ns; /* the tx timestamps for all the pending packets before this one are lost */ while ((pskb = __skb_dequeue(pending_q)) != skb) { EMAC_HWTXTSTAMP_CB(pskb)->sec = 0; EMAC_HWTXTSTAMP_CB(pskb)->ns = 0; __skb_queue_tail(q, pskb); adpt->hwtxtstamp_stats.lost++; } __skb_queue_tail(q, skb); found = true; break; } } ns = emac_reg_r32(hw, EMAC_CSR, EMAC_EMAC_WRAPPER_TX_TS_LO); sec = emac_reg_r32(hw, EMAC_CSR, EMAC_EMAC_WRAPPER_TX_TS_HI); if (!found) { emac_dbg(adpt, tx_done, "no entry(tpd=%d) found, drop tx timestamp\n", hwtxtstamp.ts_idx); adpt->hwtxtstamp_stats.drop++; } } ts_idx &= EMAC_WRAPPER_TX_TS_INX_BMSK; if ((ts_idx < txque->tpd.consume_idx) || (ts_idx > txque->tpd.last_produce_idx)) { emac_warn(hw->adpt, tx_done, "zombie timestamp desc idx %d\n", ts_idx); continue; skb_queue_walk_safe(pending_q, skb, skb_tmp) { /* No packet after this one expires */ if (!emac_skb_cb_expired(skb)) break; adpt->hwtxtstamp_stats.timeout++; emac_dbg(adpt, tx_done, "tx timestamp timeout: tpd_idx=%d\n", EMAC_SKB_CB(skb)->tpd_idx); __skb_unlink(skb, pending_q); EMAC_HWTXTSTAMP_CB(skb)->sec = 0; EMAC_HWTXTSTAMP_CB(skb)->ns = 0; __skb_queue_tail(q, skb); } } tpbuf = GET_TPD_BUFFER(txque, ts_idx); static void emac_schedule_hwtxtstamp_task(struct emac_adapter *adpt) { if (CHK_ADPT_FLAG(STATE_DOWN)) return; if (schedule_work(&adpt->hwtxtstamp_task)) adpt->hwtxtstamp_stats.sched++; } static void emac_hwtxtstamp_task_routine(struct work_struct *work) { struct emac_adapter *adpt = container_of(work, struct emac_adapter, hwtxtstamp_task); struct sk_buff *skb; struct sk_buff_head q; unsigned long flags; adpt->hwtxtstamp_stats.poll++; __skb_queue_head_init(&q); while (1) { spin_lock_irqsave(&adpt->hwtxtstamp_lock, flags); if (adpt->hwtxtstamp_pending_queue.qlen) emac_poll_hwtxtstamp(adpt); skb_queue_splice_tail_init(&adpt->hwtxtstamp_ready_queue, &q); spin_unlock_irqrestore(&adpt->hwtxtstamp_lock, flags); if (tpbuf->skb && (skb_shinfo(tpbuf->skb)->tx_flags & SKBTX_HW_TSTAMP)) { if (!q.qlen) break; while ((skb = __skb_dequeue(&q))) { struct emac_hwtxtstamp_cb *cb = EMAC_HWTXTSTAMP_CB(skb); if (cb->sec || cb->ns) { struct skb_shared_hwtstamps ts; ts.hwtstamp = ktime_set(sec, ns); ts.syststamp = ktime_add_ns(ts.hwtstamp, hw->tstamp_tx_offset); skb_tstamp_tx(tpbuf->skb, &ts); ts.hwtstamp = ktime_set(cb->sec, cb->ns); ts.syststamp = ktime_add_ns( ts.hwtstamp, adpt->hw.tstamp_tx_offset); skb_tstamp_tx(skb, &ts); adpt->hwtxtstamp_stats.deliver++; } dev_kfree_skb_any(skb); } } if (adpt->hwtxtstamp_pending_queue.qlen) emac_schedule_hwtxtstamp_task(adpt); } /* Process receive event */ Loading Loading @@ -600,7 +694,6 @@ static void emac_handle_tx(struct emac_adapter *adpt, txque->que_idx, hw_consume_idx); while (txque->tpd.consume_idx != hw_consume_idx) { emac_read_tx_tstamp_fifo(hw, txque); tpbuf = GET_TPD_BUFFER(txque, txque->tpd.consume_idx); if (tpbuf->dma) { dma_unmap_single(txque->dev, tpbuf->dma, tpbuf->length, Loading Loading @@ -822,8 +915,29 @@ static void emac_tx_map(struct emac_adapter *adpt, if (CHK_HW_FLAG(TS_TX_EN) && (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) { struct sk_buff *skb_ts = skb_clone(skb, GFP_ATOMIC); if (likely(skb_ts)) { unsigned long flags; emac_set_tpdesc_tstamp_sav(txque); skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; skb_ts->sk = skb->sk; EMAC_SKB_CB(skb_ts)->tpd_idx = txque->tpd.last_produce_idx; EMAC_SKB_CB(skb_ts)->jiffies = get_jiffies_64(); skb_shinfo(skb_ts)->tx_flags |= SKBTX_IN_PROGRESS; spin_lock_irqsave(&adpt->hwtxtstamp_lock, flags); if (adpt->hwtxtstamp_pending_queue.qlen >= EMAC_TX_POLL_HWTXTSTAMP_THRESHOLD) { emac_poll_hwtxtstamp(adpt); adpt->hwtxtstamp_stats.tx_poll++; } __skb_queue_tail(&adpt->hwtxtstamp_pending_queue, skb_ts); spin_unlock_irqrestore(&adpt->hwtxtstamp_lock, flags); adpt->hwtxtstamp_stats.tx++; emac_schedule_hwtxtstamp_task(adpt); } } /* The last buffer info contain the skb address, Loading Loading @@ -1559,6 +1673,7 @@ void emac_down(struct emac_adapter *adpt, u32 ctrl) { struct net_device *netdev = adpt->netdev; struct emac_hw *hw = &adpt->hw; unsigned long flags; int i; SET_ADPT_FLAG(STATE_DOWN); Loading @@ -1581,6 +1696,12 @@ void emac_down(struct emac_adapter *adpt, u32 ctrl) CLI_ADPT_FLAG(TASK_CHK_SGMII_REQ); del_timer_sync(&adpt->emac_timer); cancel_work_sync(&adpt->hwtxtstamp_task); spin_lock_irqsave(&adpt->hwtxtstamp_lock, flags); __skb_queue_purge(&adpt->hwtxtstamp_pending_queue); __skb_queue_purge(&adpt->hwtxtstamp_ready_queue); spin_unlock_irqrestore(&adpt->hwtxtstamp_lock, flags); if (ctrl & EMAC_HW_CTRL_RESET_MAC) emac_hw_reset_mac(hw); Loading Loading @@ -2693,6 +2814,11 @@ static int emac_probe(struct platform_device *pdev) netif_napi_add(netdev, &adpt->rx_queue[i].napi, emac_napi_rtx, 64); spin_lock_init(&adpt->hwtxtstamp_lock); skb_queue_head_init(&adpt->hwtxtstamp_pending_queue); skb_queue_head_init(&adpt->hwtxtstamp_ready_queue); INIT_WORK(&adpt->hwtxtstamp_task, emac_hwtxtstamp_task_routine); SET_HW_FLAG(VLANSTRIP_EN); SET_ADPT_FLAG(STATE_DOWN); strlcpy(netdev->name, "eth%d", sizeof(netdev->name)); Loading