diff --git a/drivers/net/ethernet/realtek/rtase/rtase_main.c b/drivers/net/ethernet/realtek/rtase/rtase_main.c index a7e8b4f50c5b0..7f683c2460034 100644 --- a/drivers/net/ethernet/realtek/rtase/rtase_main.c +++ b/drivers/net/ethernet/realtek/rtase/rtase_main.c @@ -192,6 +192,56 @@ static int rtase_alloc_desc(struct rtase_private *tp) return -ENOMEM; } +static void rtase_unmap_tx_skb(struct pci_dev *pdev, u32 len, + struct rtase_tx_desc *desc) +{ + dma_unmap_single(&pdev->dev, le64_to_cpu(desc->addr), len, + DMA_TO_DEVICE); + desc->opts1 = cpu_to_le32(RTK_OPTS1_DEBUG_VALUE); + desc->opts2 = 0x00; + desc->addr = cpu_to_le64(RTK_MAGIC_NUMBER); +} + +static void rtase_tx_clear_range(struct rtase_ring *ring, u32 start, u32 n) +{ + struct rtase_tx_desc *desc_base = ring->desc; + struct rtase_private *tp = ring->ivec->tp; + u32 i; + + for (i = 0; i < n; i++) { + u32 entry = (start + i) % RTASE_NUM_DESC; + struct rtase_tx_desc *desc = desc_base + entry; + u32 len = ring->mis.len[entry]; + struct sk_buff *skb; + + if (len == 0) + continue; + + rtase_unmap_tx_skb(tp->pdev, len, desc); + ring->mis.len[entry] = 0; + skb = ring->skbuff[entry]; + if (!skb) + continue; + + tp->stats.tx_dropped++; + dev_kfree_skb_any(skb); + ring->skbuff[entry] = NULL; + } +} + +static void rtase_tx_clear(struct rtase_private *tp) +{ + struct rtase_ring *ring; + u16 i; + + for (i = 0; i < tp->func_tx_queue_num; i++) { + ring = &tp->tx_ring[i]; + rtase_tx_clear_range(ring, ring->dirty_idx, RTASE_NUM_DESC); + ring->cur_idx = 0; + ring->dirty_idx = 0; + } +} + static void rtase_mark_to_asic(union rtase_rx_desc *desc, u32 rx_buf_sz) { u32 eor = le32_to_cpu(desc->desc_cmd.opts1) & RTASE_RING_END; @@ -410,6 +460,80 @@ static void rtase_tally_counter_clear(const struct rtase_private *tp) rtase_w32(tp, RTASE_DTCCR0, cmd | RTASE_COUNTER_RESET); } +static void rtase_irq_dis_and_clear(const struct rtase_private *tp) +{ + const struct rtase_int_vector *ivec = &tp->int_vector[0]; + u32 val1; + u16 val2; + u8 i; + + rtase_w32(tp, ivec->imr_addr, 0); + val1 = rtase_r32(tp, ivec->isr_addr); + rtase_w32(tp, ivec->isr_addr, val1); + + for (i = 1; i < tp->int_nums; i++) { + ivec = &tp->int_vector[i]; + rtase_w16(tp, ivec->imr_addr, 0); + val2 = rtase_r16(tp, ivec->isr_addr); + rtase_w16(tp, ivec->isr_addr, val2); + } +} + +static void rtase_poll_timeout(const struct rtase_private *tp, u32 cond, + u32 sleep_us, u64 timeout_us, u16 reg) +{ + int err; + u8 val; + + err = read_poll_timeout(rtase_r8, val, val & cond, sleep_us, + timeout_us, false, tp, reg); + + if (err == -ETIMEDOUT) + netdev_err(tp->dev, "poll reg 0x00%x timeout\n", reg); +} + +static void rtase_nic_reset(const struct net_device *dev) +{ + const struct rtase_private *tp = netdev_priv(dev); + u16 rx_config; + u8 val; + + rx_config = rtase_r16(tp, RTASE_RX_CONFIG_0); + rtase_w16(tp, RTASE_RX_CONFIG_0, rx_config & ~RTASE_ACCEPT_MASK); + + val = rtase_r8(tp, RTASE_MISC); + rtase_w8(tp, RTASE_MISC, val | RTASE_RX_DV_GATE_EN); + + val = rtase_r8(tp, RTASE_CHIP_CMD); + rtase_w8(tp, RTASE_CHIP_CMD, val | RTASE_STOP_REQ); + mdelay(2); + + rtase_poll_timeout(tp, RTASE_STOP_REQ_DONE, 100, 150000, + RTASE_CHIP_CMD); + + rtase_poll_timeout(tp, RTASE_TX_FIFO_EMPTY, 100, 100000, + RTASE_FIFOR); + + rtase_poll_timeout(tp, RTASE_RX_FIFO_EMPTY, 100, 100000, + RTASE_FIFOR); + + val = rtase_r8(tp, RTASE_CHIP_CMD); + rtase_w8(tp, RTASE_CHIP_CMD, val & ~(RTASE_TE | RTASE_RE)); + val = rtase_r8(tp, RTASE_CHIP_CMD); + rtase_w8(tp, RTASE_CHIP_CMD, val & ~RTASE_STOP_REQ); + + rtase_w16(tp, RTASE_RX_CONFIG_0, rx_config); +} + +static void rtase_hw_reset(const struct net_device *dev) +{ + const struct rtase_private *tp = netdev_priv(dev); + + rtase_irq_dis_and_clear(tp); + + rtase_nic_reset(dev); +} + static void rtase_nic_enable(const struct net_device *dev) { const struct rtase_private *tp = netdev_priv(dev); @@ -513,6 +637,32 @@ static int rtase_open(struct net_device *dev) return ret; } +static void rtase_down(struct net_device *dev) +{ + struct rtase_private *tp = netdev_priv(dev); + struct rtase_int_vector *ivec; + struct rtase_ring *ring, *tmp; + u32 i; + + for (i = 0; i < tp->int_nums; i++) { + ivec = &tp->int_vector[i]; + napi_disable(&ivec->napi); + list_for_each_entry_safe(ring, tmp, &ivec->ring_list, + ring_entry) + list_del(&ring->ring_entry); + } + + netif_tx_disable(dev); + + netif_carrier_off(dev); + + rtase_hw_reset(dev); + + rtase_tx_clear(tp); + + rtase_rx_clear(tp); +} + static int rtase_close(struct net_device *dev) { struct rtase_private *tp = netdev_priv(dev);