/** * ixgbe_ptp_tx_hwtstamp_work * @work: pointer to the work struct * * This work item polls TSYNCTXCTL valid bit to determine when a Tx hardware * timestamp has been taken for the current skb. It is necesary, because the * descriptor's "done" bit does not correlate with the timestamp event. */ static void ixgbe_ptp_tx_hwtstamp_work(struct work_struct *work) { struct ixgbe_adapter *adapter = container_of(work, struct ixgbe_adapter, ptp_tx_work); struct ixgbe_hw *hw = &adapter->hw; bool timeout = time_is_before_jiffies(adapter->ptp_tx_start + IXGBE_PTP_TX_TIMEOUT); u32 tsynctxctl; /* we have to have a valid skb */ if (!adapter->ptp_tx_skb) return; if (timeout) { dev_kfree_skb_any(adapter->ptp_tx_skb); adapter->ptp_tx_skb = NULL; adapter->tx_hwtstamp_timeouts++; e_warn(drv, "clearing Tx Timestamp hang"); return; } tsynctxctl = IXGBE_READ_REG(hw, IXGBE_TSYNCTXCTL); if (tsynctxctl & IXGBE_TSYNCTXCTL_VALID) ixgbe_ptp_tx_hwtstamp(adapter); else /* reschedule to keep checking if it's not available yet */ schedule_work(&adapter->ptp_tx_work); }
/** * ixgbe_ptp_rx_hang - detect error case when Rx timestamp registers latched * @adapter: private network adapter structure * * this watchdog task is scheduled to detect error case where hardware has * dropped an Rx packet that was timestamped when the ring is full. The * particular error is rare but leaves the device in a state unable to timestamp * any future packets. */ void ixgbe_ptp_rx_hang(struct ixgbe_adapter *adapter) { struct ixgbe_hw *hw = &adapter->hw; struct ixgbe_ring *rx_ring; u32 tsyncrxctl = IXGBE_READ_REG(hw, IXGBE_TSYNCRXCTL); unsigned long rx_event; int n; /* if we don't have a valid timestamp in the registers, just update the * timeout counter and exit */ if (!(tsyncrxctl & IXGBE_TSYNCRXCTL_VALID)) { adapter->last_rx_ptp_check = jiffies; return; } /* determine the most recent watchdog or rx_timestamp event */ rx_event = adapter->last_rx_ptp_check; for (n = 0; n < adapter->num_rx_queues; n++) { rx_ring = adapter->rx_ring[n]; if (time_after(rx_ring->last_rx_timestamp, rx_event)) rx_event = rx_ring->last_rx_timestamp; } /* only need to read the high RXSTMP register to clear the lock */ if (time_is_before_jiffies(rx_event + 5*HZ)) { IXGBE_READ_REG(hw, IXGBE_RXSTMPH); adapter->last_rx_ptp_check = jiffies; adapter->rx_hwtstamp_cleared++; e_warn(drv, "clearing RX Timestamp hang"); } }
/** * ixgbe_fcoe_ddp_setup - called to set up ddp context * @netdev: the corresponding net_device * @xid: the exchange id requesting ddp * @sgl: the scatter-gather list for this request * @sgc: the number of scatter-gather items * * Returns : 1 for success and 0 for no ddp */ static int ixgbe_fcoe_ddp_setup(struct net_device *netdev, u16 xid, struct scatterlist *sgl, unsigned int sgc, int target_mode) { struct ixgbe_adapter *adapter; struct ixgbe_hw *hw; struct ixgbe_fcoe *fcoe; struct ixgbe_fcoe_ddp *ddp; struct ixgbe_fcoe_ddp_pool *ddp_pool; struct scatterlist *sg; unsigned int i, j, dmacount; unsigned int len; static const unsigned int bufflen = IXGBE_FCBUFF_MIN; unsigned int firstoff = 0; unsigned int lastsize; unsigned int thisoff = 0; unsigned int thislen = 0; u32 fcbuff, fcdmarw, fcfltrw, fcrxctl; dma_addr_t addr = 0; if (!netdev || !sgl) return 0; adapter = netdev_priv(netdev); if (xid >= IXGBE_FCOE_DDP_MAX) { e_warn(drv, "xid=0x%x out-of-range\n", xid); return 0; } /* no DDP if we are already down or resetting */ if (test_bit(__IXGBE_DOWN, &adapter->state) || test_bit(__IXGBE_RESETTING, &adapter->state)) return 0; fcoe = &adapter->fcoe; ddp = &fcoe->ddp[xid]; if (ddp->sgl) { e_err(drv, "xid 0x%x w/ non-null sgl=%p nents=%d\n", xid, ddp->sgl, ddp->sgc); return 0; } ixgbe_fcoe_clear_ddp(ddp); if (!fcoe->ddp_pool) { e_warn(drv, "No ddp_pool resources allocated\n"); return 0; } ddp_pool = per_cpu_ptr(fcoe->ddp_pool, get_cpu()); if (!ddp_pool->pool) { e_warn(drv, "xid=0x%x no ddp pool for fcoe\n", xid); goto out_noddp; } /* setup dma from scsi command sgl */ dmacount = dma_map_sg(&adapter->pdev->dev, sgl, sgc, DMA_FROM_DEVICE); if (dmacount == 0) { e_err(drv, "xid 0x%x DMA map error\n", xid); goto out_noddp; } /* alloc the udl from per cpu ddp pool */ ddp->udl = dma_pool_alloc(ddp_pool->pool, GFP_ATOMIC, &ddp->udp); if (!ddp->udl) { e_err(drv, "failed allocated ddp context\n"); goto out_noddp_unmap; } ddp->pool = ddp_pool->pool; ddp->sgl = sgl; ddp->sgc = sgc; j = 0; for_each_sg(sgl, sg, dmacount, i) { addr = sg_dma_address(sg); len = sg_dma_len(sg); while (len) { /* max number of buffers allowed in one DDP context */ if (j >= IXGBE_BUFFCNT_MAX) { ddp_pool->noddp++; goto out_noddp_free; } /* get the offset of length of current buffer */ thisoff = addr & ((dma_addr_t)bufflen - 1); thislen = min((bufflen - thisoff), len); /* * all but the 1st buffer (j == 0) * must be aligned on bufflen */ if ((j != 0) && (thisoff)) goto out_noddp_free; /* * all but the last buffer * ((i == (dmacount - 1)) && (thislen == len)) * must end at bufflen */ if (((i != (dmacount - 1)) || (thislen != len)) && ((thislen + thisoff) != bufflen)) goto out_noddp_free; ddp->udl[j] = (u64)(addr - thisoff); /* only the first buffer may have none-zero offset */ if (j == 0) firstoff = thisoff; len -= thislen; addr += thislen; j++; } }