Commit 5403d39b authored by David S. Miller's avatar David S. Miller

Merge branch '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/nex

t-queue

Tony Nguyen says:

====================
Intel Wired LAN Driver Updates 2024-01-02 (ice)

This series contains updates to ice driver only.

Karol adds support for capable devices to receive timestamp via
interrupt rather than polling to allow for less delay.

Andrii adds support switchdev hardware packet mirroring.

Jake reworks VF rebuild to avoid destroying objects that do not need to
be.

Jan S removes reporting of rx_len_errors as they are incorrectly reported
by hardware.

Jan G adds const modifier to some uses that are applicable.

Kunwu Chan adds some checks for failed memory allocations.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents a562c0a2 3027e7b1
......@@ -518,7 +518,6 @@ enum ice_pf_flags {
};
enum ice_misc_thread_tasks {
ICE_MISC_THREAD_EXTTS_EVENT,
ICE_MISC_THREAD_TX_TSTAMP,
ICE_MISC_THREAD_NBITS /* must be last */
};
......@@ -609,6 +608,7 @@ struct ice_pf {
u32 hw_csum_rx_error;
u32 oicr_err_reg;
struct msi_map oicr_irq; /* Other interrupt cause MSIX vector */
struct msi_map ll_ts_irq; /* LL_TS interrupt MSIX vector */
u16 max_pf_txqs; /* Total Tx queues PF wide */
u16 max_pf_rxqs; /* Total Rx queues PF wide */
u16 num_lan_msix; /* Total MSIX vectors for base driver */
......@@ -633,6 +633,7 @@ struct ice_pf {
unsigned long tx_timeout_last_recovery;
u32 tx_timeout_recovery_level;
char int_name[ICE_INT_NAME_STR_LEN];
char int_name_ll_ts[ICE_INT_NAME_STR_LEN];
struct auxiliary_device *adev;
int aux_idx;
u32 sw_int_count;
......
......@@ -278,7 +278,7 @@ static u16 ice_calc_txq_handle(struct ice_vsi *vsi, struct ice_tx_ring *ring, u8
*/
static u16 ice_eswitch_calc_txq_handle(struct ice_tx_ring *ring)
{
struct ice_vsi *vsi = ring->vsi;
const struct ice_vsi *vsi = ring->vsi;
int i;
ice_for_each_txq(vsi, i) {
......@@ -975,7 +975,7 @@ ice_cfg_rxq_interrupt(struct ice_vsi *vsi, u16 rxq, u16 msix_idx, u16 itr_idx)
* @hw: pointer to the HW structure
* @q_vector: interrupt vector to trigger the software interrupt for
*/
void ice_trigger_sw_intr(struct ice_hw *hw, struct ice_q_vector *q_vector)
void ice_trigger_sw_intr(struct ice_hw *hw, const struct ice_q_vector *q_vector)
{
wr32(hw, GLINT_DYN_CTL(q_vector->reg_idx),
(ICE_ITR_NONE << GLINT_DYN_CTL_ITR_INDX_S) |
......@@ -1050,7 +1050,7 @@ ice_vsi_stop_tx_ring(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src,
* are needed for stopping Tx queue
*/
void
ice_fill_txq_meta(struct ice_vsi *vsi, struct ice_tx_ring *ring,
ice_fill_txq_meta(const struct ice_vsi *vsi, struct ice_tx_ring *ring,
struct ice_txq_meta *txq_meta)
{
struct ice_channel *ch = ring->ch;
......
......@@ -22,12 +22,12 @@ void
ice_cfg_txq_interrupt(struct ice_vsi *vsi, u16 txq, u16 msix_idx, u16 itr_idx);
void
ice_cfg_rxq_interrupt(struct ice_vsi *vsi, u16 rxq, u16 msix_idx, u16 itr_idx);
void ice_trigger_sw_intr(struct ice_hw *hw, struct ice_q_vector *q_vector);
void ice_trigger_sw_intr(struct ice_hw *hw, const struct ice_q_vector *q_vector);
int
ice_vsi_stop_tx_ring(struct ice_vsi *vsi, enum ice_disq_rst_src rst_src,
u16 rel_vmvf_num, struct ice_tx_ring *ring,
struct ice_txq_meta *txq_meta);
void
ice_fill_txq_meta(struct ice_vsi *vsi, struct ice_tx_ring *ring,
ice_fill_txq_meta(const struct ice_vsi *vsi, struct ice_tx_ring *ring,
struct ice_txq_meta *txq_meta);
#endif /* _ICE_BASE_H_ */
......@@ -2451,6 +2451,7 @@ ice_parse_1588_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p,
info->tmr1_ena = ((number & ICE_TS_TMR1_ENA_M) != 0);
info->ts_ll_read = ((number & ICE_TS_LL_TX_TS_READ_M) != 0);
info->ts_ll_int_read = ((number & ICE_TS_LL_TX_TS_INT_READ_M) != 0);
info->ena_ports = logical_id;
info->tmr_own_map = phys_id;
......@@ -2471,6 +2472,8 @@ ice_parse_1588_dev_caps(struct ice_hw *hw, struct ice_hw_dev_caps *dev_p,
info->tmr1_ena);
ice_debug(hw, ICE_DBG_INIT, "dev caps: ts_ll_read = %u\n",
info->ts_ll_read);
ice_debug(hw, ICE_DBG_INIT, "dev caps: ts_ll_int_read = %u\n",
info->ts_ll_int_read);
ice_debug(hw, ICE_DBG_INIT, "dev caps: ieee_1588 ena_ports = %u\n",
info->ena_ports);
ice_debug(hw, ICE_DBG_INIT, "dev caps: tmr_own_map = %u\n",
......
......@@ -129,7 +129,6 @@ static const struct ice_stats ice_gstrings_pf_stats[] = {
ICE_PF_STAT("rx_oversize.nic", stats.rx_oversize),
ICE_PF_STAT("rx_jabber.nic", stats.rx_jabber),
ICE_PF_STAT("rx_csum_bad.nic", hw_csum_rx_error),
ICE_PF_STAT("rx_length_errors.nic", stats.rx_len_errors),
ICE_PF_STAT("rx_dropped.nic", stats.eth.rx_discards),
ICE_PF_STAT("rx_crc_errors.nic", stats.crc_errors),
ICE_PF_STAT("illegal_bytes.nic", stats.illegal_bytes),
......
......@@ -200,6 +200,8 @@
#define GLINT_VECT2FUNC_PF_NUM_M ICE_M(0x7, 12)
#define GLINT_VECT2FUNC_IS_PF_S 16
#define GLINT_VECT2FUNC_IS_PF_M BIT(16)
#define PFINT_ALLOC 0x001D2600
#define PFINT_ALLOC_FIRST ICE_M(0x7FF, 0)
#define PFINT_FW_CTL 0x0016C800
#define PFINT_FW_CTL_MSIX_INDX_M ICE_M(0x7FF, 0)
#define PFINT_FW_CTL_ITR_INDX_S 11
......
......@@ -3046,6 +3046,7 @@ static int ice_xdp(struct net_device *dev, struct netdev_bpf *xdp)
static void ice_ena_misc_vector(struct ice_pf *pf)
{
struct ice_hw *hw = &pf->hw;
u32 pf_intr_start_offset;
u32 val;
/* Disable anti-spoof detection interrupt to prevent spurious event
......@@ -3074,6 +3075,47 @@ static void ice_ena_misc_vector(struct ice_pf *pf)
/* SW_ITR_IDX = 0, but don't change INTENA */
wr32(hw, GLINT_DYN_CTL(pf->oicr_irq.index),
GLINT_DYN_CTL_SW_ITR_INDX_M | GLINT_DYN_CTL_INTENA_MSK_M);
if (!pf->hw.dev_caps.ts_dev_info.ts_ll_int_read)
return;
pf_intr_start_offset = rd32(hw, PFINT_ALLOC) & PFINT_ALLOC_FIRST;
wr32(hw, GLINT_DYN_CTL(pf->ll_ts_irq.index + pf_intr_start_offset),
GLINT_DYN_CTL_SW_ITR_INDX_M | GLINT_DYN_CTL_INTENA_MSK_M);
}
/**
* ice_ll_ts_intr - ll_ts interrupt handler
* @irq: interrupt number
* @data: pointer to a q_vector
*/
static irqreturn_t ice_ll_ts_intr(int __always_unused irq, void *data)
{
struct ice_pf *pf = data;
u32 pf_intr_start_offset;
struct ice_ptp_tx *tx;
unsigned long flags;
struct ice_hw *hw;
u32 val;
u8 idx;
hw = &pf->hw;
tx = &pf->ptp.port.tx;
spin_lock_irqsave(&tx->lock, flags);
ice_ptp_complete_tx_single_tstamp(tx);
idx = find_next_bit_wrap(tx->in_use, tx->len,
tx->last_ll_ts_idx_read + 1);
if (idx != tx->len)
ice_ptp_req_tx_single_tstamp(tx, idx);
spin_unlock_irqrestore(&tx->lock, flags);
val = GLINT_DYN_CTL_INTENA_M | GLINT_DYN_CTL_CLEARPBA_M |
(ICE_ITR_NONE << GLINT_DYN_CTL_ITR_INDX_S);
pf_intr_start_offset = rd32(hw, PFINT_ALLOC) & PFINT_ALLOC_FIRST;
wr32(hw, GLINT_DYN_CTL(pf->ll_ts_irq.index + pf_intr_start_offset),
val);
return IRQ_HANDLED;
}
/**
......@@ -3084,6 +3126,7 @@ static void ice_ena_misc_vector(struct ice_pf *pf)
static irqreturn_t ice_misc_intr(int __always_unused irq, void *data)
{
struct ice_pf *pf = (struct ice_pf *)data;
irqreturn_t ret = IRQ_HANDLED;
struct ice_hw *hw = &pf->hw;
struct device *dev;
u32 oicr, ena_mask;
......@@ -3165,8 +3208,22 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data)
if (oicr & PFINT_OICR_TSYN_TX_M) {
ena_mask &= ~PFINT_OICR_TSYN_TX_M;
if (ice_ptp_pf_handles_tx_interrupt(pf))
if (ice_pf_state_is_nominal(pf) &&
pf->hw.dev_caps.ts_dev_info.ts_ll_int_read) {
struct ice_ptp_tx *tx = &pf->ptp.port.tx;
unsigned long flags;
u8 idx;
spin_lock_irqsave(&tx->lock, flags);
idx = find_next_bit_wrap(tx->in_use, tx->len,
tx->last_ll_ts_idx_read + 1);
if (idx != tx->len)
ice_ptp_req_tx_single_tstamp(tx, idx);
spin_unlock_irqrestore(&tx->lock, flags);
} else if (ice_ptp_pf_handles_tx_interrupt(pf)) {
set_bit(ICE_MISC_THREAD_TX_TSTAMP, pf->misc_thread);
ret = IRQ_WAKE_THREAD;
}
}
if (oicr & PFINT_OICR_TSYN_EVNT_M) {
......@@ -3182,7 +3239,7 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data)
GLTSYN_STAT_EVENT1_M |
GLTSYN_STAT_EVENT2_M);
set_bit(ICE_MISC_THREAD_EXTTS_EVENT, pf->misc_thread);
ice_ptp_extts_event(pf);
}
}
......@@ -3205,8 +3262,11 @@ static irqreturn_t ice_misc_intr(int __always_unused irq, void *data)
set_bit(ICE_PFR_REQ, pf->state);
}
}
ice_service_task_schedule(pf);
if (ret == IRQ_HANDLED)
ice_irq_dynamic_ena(hw, NULL, NULL);
return IRQ_WAKE_THREAD;
return ret;
}
/**
......@@ -3222,12 +3282,7 @@ static irqreturn_t ice_misc_intr_thread_fn(int __always_unused irq, void *data)
hw = &pf->hw;
if (ice_is_reset_in_progress(pf->state))
return IRQ_HANDLED;
ice_service_task_schedule(pf);
if (test_and_clear_bit(ICE_MISC_THREAD_EXTTS_EVENT, pf->misc_thread))
ice_ptp_extts_event(pf);
goto skip_irq;
if (test_and_clear_bit(ICE_MISC_THREAD_TX_TSTAMP, pf->misc_thread)) {
/* Process outstanding Tx timestamps. If there is more work,
......@@ -3239,6 +3294,7 @@ static irqreturn_t ice_misc_intr_thread_fn(int __always_unused irq, void *data)
}
}
skip_irq:
ice_irq_dynamic_ena(hw, NULL, NULL);
return IRQ_HANDLED;
......@@ -3268,6 +3324,20 @@ static void ice_dis_ctrlq_interrupts(struct ice_hw *hw)
ice_flush(hw);
}
/**
* ice_free_irq_msix_ll_ts- Unroll ll_ts vector setup
* @pf: board private structure
*/
static void ice_free_irq_msix_ll_ts(struct ice_pf *pf)
{
int irq_num = pf->ll_ts_irq.virq;
synchronize_irq(irq_num);
devm_free_irq(ice_pf_to_dev(pf), irq_num, pf);
ice_free_irq(pf, pf->ll_ts_irq);
}
/**
* ice_free_irq_msix_misc - Unroll misc vector setup
* @pf: board private structure
......@@ -3287,6 +3357,8 @@ static void ice_free_irq_msix_misc(struct ice_pf *pf)
devm_free_irq(ice_pf_to_dev(pf), misc_irq_num, pf);
ice_free_irq(pf, pf->oicr_irq);
if (pf->hw.dev_caps.ts_dev_info.ts_ll_int_read)
ice_free_irq_msix_ll_ts(pf);
}
/**
......@@ -3312,10 +3384,12 @@ static void ice_ena_ctrlq_interrupts(struct ice_hw *hw, u16 reg_idx)
PFINT_MBX_CTL_CAUSE_ENA_M);
wr32(hw, PFINT_MBX_CTL, val);
/* This enables Sideband queue Interrupt causes */
val = ((reg_idx & PFINT_SB_CTL_MSIX_INDX_M) |
PFINT_SB_CTL_CAUSE_ENA_M);
wr32(hw, PFINT_SB_CTL, val);
if (!hw->dev_caps.ts_dev_info.ts_ll_int_read) {
/* enable Sideband queue Interrupt causes */
val = ((reg_idx & PFINT_SB_CTL_MSIX_INDX_M) |
PFINT_SB_CTL_CAUSE_ENA_M);
wr32(hw, PFINT_SB_CTL, val);
}
ice_flush(hw);
}
......@@ -3332,13 +3406,17 @@ static int ice_req_irq_msix_misc(struct ice_pf *pf)
{
struct device *dev = ice_pf_to_dev(pf);
struct ice_hw *hw = &pf->hw;
struct msi_map oicr_irq;
u32 pf_intr_start_offset;
struct msi_map irq;
int err = 0;
if (!pf->int_name[0])
snprintf(pf->int_name, sizeof(pf->int_name) - 1, "%s-%s:misc",
dev_driver_string(dev), dev_name(dev));
if (!pf->int_name_ll_ts[0])
snprintf(pf->int_name_ll_ts, sizeof(pf->int_name_ll_ts) - 1,
"%s-%s:ll_ts", dev_driver_string(dev), dev_name(dev));
/* Do not request IRQ but do enable OICR interrupt since settings are
* lost during reset. Note that this function is called only during
* rebuild path and not while reset is in progress.
......@@ -3347,11 +3425,11 @@ static int ice_req_irq_msix_misc(struct ice_pf *pf)
goto skip_req_irq;
/* reserve one vector in irq_tracker for misc interrupts */
oicr_irq = ice_alloc_irq(pf, false);
if (oicr_irq.index < 0)
return oicr_irq.index;
irq = ice_alloc_irq(pf, false);
if (irq.index < 0)
return irq.index;
pf->oicr_irq = oicr_irq;
pf->oicr_irq = irq;
err = devm_request_threaded_irq(dev, pf->oicr_irq.virq, ice_misc_intr,
ice_misc_intr_thread_fn, 0,
pf->int_name, pf);
......@@ -3362,10 +3440,34 @@ static int ice_req_irq_msix_misc(struct ice_pf *pf)
return err;
}
/* reserve one vector in irq_tracker for ll_ts interrupt */
if (!pf->hw.dev_caps.ts_dev_info.ts_ll_int_read)
goto skip_req_irq;
irq = ice_alloc_irq(pf, false);
if (irq.index < 0)
return irq.index;
pf->ll_ts_irq = irq;
err = devm_request_irq(dev, pf->ll_ts_irq.virq, ice_ll_ts_intr, 0,
pf->int_name_ll_ts, pf);
if (err) {
dev_err(dev, "devm_request_irq for %s failed: %d\n",
pf->int_name_ll_ts, err);
ice_free_irq(pf, pf->ll_ts_irq);
return err;
}
skip_req_irq:
ice_ena_misc_vector(pf);
ice_ena_ctrlq_interrupts(hw, pf->oicr_irq.index);
/* This enables LL TS interrupt */
pf_intr_start_offset = rd32(hw, PFINT_ALLOC) & PFINT_ALLOC_FIRST;
if (pf->hw.dev_caps.ts_dev_info.ts_ll_int_read)
wr32(hw, PFINT_SB_CTL,
((pf->ll_ts_irq.index + pf_intr_start_offset) &
PFINT_SB_CTL_MSIX_INDX_M) | PFINT_SB_CTL_CAUSE_ENA_M);
wr32(hw, GLINT_ITR(ICE_RX_ITR, pf->oicr_irq.index),
ITR_REG_ALIGN(ICE_ITR_8K) >> ICE_ITR_GRAN_S);
......@@ -6732,13 +6834,11 @@ void ice_update_vsi_stats(struct ice_vsi *vsi)
cur_ns->rx_crc_errors = pf->stats.crc_errors;
cur_ns->rx_errors = pf->stats.crc_errors +
pf->stats.illegal_bytes +
pf->stats.rx_len_errors +
pf->stats.rx_undersize +
pf->hw_csum_rx_error +
pf->stats.rx_jabber +
pf->stats.rx_fragments +
pf->stats.rx_oversize;
cur_ns->rx_length_errors = pf->stats.rx_len_errors;
/* record drops from the port level */
cur_ns->rx_missed_errors = pf->stats.eth.rx_discards;
}
......@@ -6878,9 +6978,6 @@ void ice_update_pf_stats(struct ice_pf *pf)
&prev_ps->mac_remote_faults,
&cur_ps->mac_remote_faults);
ice_stat_update32(hw, GLPRT_RLEC(port), pf->stat_prev_loaded,
&prev_ps->rx_len_errors, &cur_ps->rx_len_errors);
ice_stat_update32(hw, GLPRT_RUC(port), pf->stat_prev_loaded,
&prev_ps->rx_undersize, &cur_ps->rx_undersize);
......
......@@ -524,6 +524,119 @@ ice_ptp_is_tx_tracker_up(struct ice_ptp_tx *tx)
return tx->init && !tx->calibrating;
}
/**
* ice_ptp_req_tx_single_tstamp - Request Tx timestamp for a port from FW
* @tx: the PTP Tx timestamp tracker
* @idx: index of the timestamp to request
*/
void ice_ptp_req_tx_single_tstamp(struct ice_ptp_tx *tx, u8 idx)
{
struct ice_ptp_port *ptp_port;
struct sk_buff *skb;
struct ice_pf *pf;
if (!tx->init)
return;
ptp_port = container_of(tx, struct ice_ptp_port, tx);
pf = ptp_port_to_pf(ptp_port);
/* Drop packets which have waited for more than 2 seconds */
if (time_is_before_jiffies(tx->tstamps[idx].start + 2 * HZ)) {
/* Count the number of Tx timestamps that timed out */
pf->ptp.tx_hwtstamp_timeouts++;
skb = tx->tstamps[idx].skb;
tx->tstamps[idx].skb = NULL;
clear_bit(idx, tx->in_use);
dev_kfree_skb_any(skb);
return;
}
ice_trace(tx_tstamp_fw_req, tx->tstamps[idx].skb, idx);
/* Write TS index to read to the PF register so the FW can read it */
wr32(&pf->hw, PF_SB_ATQBAL,
TS_LL_READ_TS_INTR | FIELD_PREP(TS_LL_READ_TS_IDX, idx) |
TS_LL_READ_TS);
tx->last_ll_ts_idx_read = idx;
}
/**
* ice_ptp_complete_tx_single_tstamp - Complete Tx timestamp for a port
* @tx: the PTP Tx timestamp tracker
*/
void ice_ptp_complete_tx_single_tstamp(struct ice_ptp_tx *tx)
{
struct skb_shared_hwtstamps shhwtstamps = {};
u8 idx = tx->last_ll_ts_idx_read;
struct ice_ptp_port *ptp_port;
u64 raw_tstamp, tstamp;
bool drop_ts = false;
struct sk_buff *skb;
struct ice_pf *pf;
u32 val;
if (!tx->init || tx->last_ll_ts_idx_read < 0)
return;
ptp_port = container_of(tx, struct ice_ptp_port, tx);
pf = ptp_port_to_pf(ptp_port);
ice_trace(tx_tstamp_fw_done, tx->tstamps[idx].skb, idx);
val = rd32(&pf->hw, PF_SB_ATQBAL);
/* When the bit is cleared, the TS is ready in the register */
if (val & TS_LL_READ_TS) {
dev_err(ice_pf_to_dev(pf), "Failed to get the Tx tstamp - FW not ready");
return;
}
/* High 8 bit value of the TS is on the bits 16:23 */
raw_tstamp = FIELD_GET(TS_LL_READ_TS_HIGH, val);
raw_tstamp <<= 32;
/* Read the low 32 bit value */
raw_tstamp |= (u64)rd32(&pf->hw, PF_SB_ATQBAH);
/* For PHYs which don't implement a proper timestamp ready bitmap,
* verify that the timestamp value is different from the last cached
* timestamp. If it is not, skip this for now assuming it hasn't yet
* been captured by hardware.
*/
if (!drop_ts && tx->verify_cached &&
raw_tstamp == tx->tstamps[idx].cached_tstamp)
return;
if (tx->verify_cached && raw_tstamp)
tx->tstamps[idx].cached_tstamp = raw_tstamp;
clear_bit(idx, tx->in_use);
skb = tx->tstamps[idx].skb;
tx->tstamps[idx].skb = NULL;
if (test_and_clear_bit(idx, tx->stale))
drop_ts = true;
if (!skb)
return;
if (drop_ts) {
dev_kfree_skb_any(skb);
return;
}
/* Extend the timestamp using cached PHC time */
tstamp = ice_ptp_extend_40b_ts(pf, raw_tstamp);
if (tstamp) {
shhwtstamps.hwtstamp = ns_to_ktime(tstamp);
ice_trace(tx_tstamp_complete, skb, idx);
}
skb_tstamp_tx(skb, &shhwtstamps);
dev_kfree_skb_any(skb);
}
/**
* ice_ptp_process_tx_tstamp - Process Tx timestamps for a port
* @tx: the PTP Tx timestamp tracker
......@@ -575,6 +688,7 @@ ice_ptp_is_tx_tracker_up(struct ice_ptp_tx *tx)
static void ice_ptp_process_tx_tstamp(struct ice_ptp_tx *tx)
{
struct ice_ptp_port *ptp_port;
unsigned long flags;
struct ice_pf *pf;
struct ice_hw *hw;
u64 tstamp_ready;
......@@ -646,7 +760,7 @@ static void ice_ptp_process_tx_tstamp(struct ice_ptp_tx *tx)
drop_ts = true;
skip_ts_read:
spin_lock(&tx->lock);
spin_lock_irqsave(&tx->lock, flags);
if (tx->verify_cached && raw_tstamp)
tx->tstamps[idx].cached_tstamp = raw_tstamp;
clear_bit(idx, tx->in_use);
......@@ -654,7 +768,7 @@ static void ice_ptp_process_tx_tstamp(struct ice_ptp_tx *tx)
tx->tstamps[idx].skb = NULL;
if (test_and_clear_bit(idx, tx->stale))
drop_ts = true;
spin_unlock(&tx->lock);
spin_unlock_irqrestore(&tx->lock, flags);
/* It is unlikely but possible that the SKB will have been
* flushed at this point due to link change or teardown.
......@@ -724,6 +838,7 @@ static enum ice_tx_tstamp_work ice_ptp_tx_tstamp_owner(struct ice_pf *pf)
static enum ice_tx_tstamp_work ice_ptp_tx_tstamp(struct ice_ptp_tx *tx)
{
bool more_timestamps;
unsigned long flags;
if (!tx->init)
return ICE_TX_TSTAMP_WORK_DONE;
......@@ -732,9 +847,9 @@ static enum ice_tx_tstamp_work ice_ptp_tx_tstamp(struct ice_ptp_tx *tx)
ice_ptp_process_tx_tstamp(tx);
/* Check if there are outstanding Tx timestamps */
spin_lock(&tx->lock);
spin_lock_irqsave(&tx->lock, flags);
more_timestamps = tx->init && !bitmap_empty(tx->in_use, tx->len);
spin_unlock(&tx->lock);
spin_unlock_irqrestore(&tx->lock, flags);
if (more_timestamps)
return ICE_TX_TSTAMP_WORK_PENDING;
......@@ -771,6 +886,7 @@ ice_ptp_alloc_tx_tracker(struct ice_ptp_tx *tx)
tx->in_use = in_use;
tx->stale = stale;
tx->init = 1;
tx->last_ll_ts_idx_read = -1;
spin_lock_init(&tx->lock);
......@@ -788,6 +904,7 @@ static void
ice_ptp_flush_tx_tracker(struct ice_pf *pf, struct ice_ptp_tx *tx)
{
struct ice_hw *hw = &pf->hw;
unsigned long flags;
u64 tstamp_ready;
int err;
u8 idx;
......@@ -811,12 +928,12 @@ ice_ptp_flush_tx_tracker(struct ice_pf *pf, struct ice_ptp_tx *tx)
if (!hw->reset_ongoing && (tstamp_ready & BIT_ULL(phy_idx)))
ice_clear_phy_tstamp(hw, tx->block, phy_idx);
spin_lock(&tx->lock);
spin_lock_irqsave(&tx->lock, flags);
skb = tx->tstamps[idx].skb;
tx->tstamps[idx].skb = NULL;
clear_bit(idx, tx->in_use);
clear_bit(idx, tx->stale);
spin_unlock(&tx->lock);
spin_unlock_irqrestore(&tx->lock, flags);
/* Count the number of Tx timestamps flushed */
pf->ptp.tx_hwtstamp_flushed++;
......@@ -840,9 +957,11 @@ ice_ptp_flush_tx_tracker(struct ice_pf *pf, struct ice_ptp_tx *tx)
static void
ice_ptp_mark_tx_tracker_stale(struct ice_ptp_tx *tx)
{
spin_lock(&tx->lock);
unsigned long flags;
spin_lock_irqsave(&tx->lock, flags);
bitmap_or(tx->stale, tx->stale, tx->in_use, tx->len);
spin_unlock(&tx->lock);
spin_unlock_irqrestore(&tx->lock, flags);
}
/**
......@@ -855,9 +974,11 @@ ice_ptp_mark_tx_tracker_stale(struct ice_ptp_tx *tx)
static void
ice_ptp_release_tx_tracker(struct ice_pf *pf, struct ice_ptp_tx *tx)
{
spin_lock(&tx->lock);
unsigned long flags;
spin_lock_irqsave(&tx->lock, flags);
tx->init = 0;
spin_unlock(&tx->lock);
spin_unlock_irqrestore(&tx->lock, flags);
/* wait for potentially outstanding interrupt to complete */
synchronize_irq(pf->oicr_irq.virq);
......@@ -1257,6 +1378,7 @@ ice_ptp_port_phy_restart(struct ice_ptp_port *ptp_port)
struct ice_pf *pf = ptp_port_to_pf(ptp_port);
u8 port = ptp_port->port_num;
struct ice_hw *hw = &pf->hw;
unsigned long flags;
int err;
if (ice_is_e810(hw))
......@@ -1270,9 +1392,9 @@ ice_ptp_port_phy_restart(struct ice_ptp_port *ptp_port)
kthread_cancel_delayed_work_sync(&ptp_port->ov_work);
/* temporarily disable Tx timestamps while calibrating PHY offset */
spin_lock(&ptp_port->tx.lock);
spin_lock_irqsave(&ptp_port->tx.lock, flags);
ptp_port->tx.calibrating = true;
spin_unlock(&ptp_port->tx.lock);
spin_unlock_irqrestore(&ptp_port->tx.lock, flags);
ptp_port->tx_fifo_busy_cnt = 0;
/* Start the PHY timer in Vernier mode */
......@@ -1281,9 +1403,9 @@ ice_ptp_port_phy_restart(struct ice_ptp_port *ptp_port)
goto out_unlock;
/* Enable Tx timestamps right away */
spin_lock(&ptp_port->tx.lock);
spin_lock_irqsave(&ptp_port->tx.lock, flags);
ptp_port->tx.calibrating = false;
spin_unlock(&ptp_port->tx.lock);
spin_unlock_irqrestore(&ptp_port->tx.lock, flags);
kthread_queue_delayed_work(pf->ptp.kworker, &ptp_port->ov_work, 0);
......@@ -2373,18 +2495,23 @@ static long ice_ptp_create_clock(struct ice_pf *pf)
*/
s8 ice_ptp_request_ts(struct ice_ptp_tx *tx, struct sk_buff *skb)
{
unsigned long flags;
u8 idx;
spin_lock(&tx->lock);
spin_lock_irqsave(&tx->lock, flags);
/* Check that this tracker is accepting new timestamp requests */
if (!ice_ptp_is_tx_tracker_up(tx)) {
spin_unlock(&tx->lock);
spin_unlock_irqrestore(&tx->lock, flags);
return -1;
}
/* Find and set the first available index */
idx = find_first_zero_bit(tx->in_use, tx->len);
idx = find_next_zero_bit(tx->in_use, tx->len,
tx->last_ll_ts_idx_read + 1);
if (idx == tx->len)
idx = find_first_zero_bit(tx->in_use, tx->len);
if (idx < tx->len) {
/* We got a valid index that no other thread could have set. Store
* a reference to the skb and the start time to allow discarding old
......@@ -2398,7 +2525,7 @@ s8 ice_ptp_request_ts(struct ice_ptp_tx *tx, struct sk_buff *skb)
ice_trace(tx_tstamp_request, skb, idx);
}
spin_unlock(&tx->lock);
spin_unlock_irqrestore(&tx->lock, flags);
/* return the appropriate PHY timestamp register index, -1 if no
* indexes were available.
......@@ -2736,6 +2863,8 @@ static int ice_ptp_register_auxbus_driver(struct ice_pf *pf)
name = devm_kasprintf(dev, GFP_KERNEL, "ptp_aux_dev_%u_%u_clk%u",
pf->pdev->bus->number, PCI_SLOT(pf->pdev->devfn),
ice_get_ptp_src_clock_index(&pf->hw));
if (!name)
return -ENOMEM;
aux_driver->name = name;
aux_driver->shutdown = ice_ptp_auxbus_shutdown;
......@@ -2982,6 +3111,8 @@ static int ice_ptp_create_auxbus_device(struct ice_pf *pf)
name = devm_kasprintf(dev, GFP_KERNEL, "ptp_aux_dev_%u_%u_clk%u",
pf->pdev->bus->number, PCI_SLOT(pf->pdev->devfn),
ice_get_ptp_src_clock_index(&pf->hw));
if (!name)
return -ENOMEM;
aux_dev->name = name;
aux_dev->id = id;
......
......@@ -131,6 +131,7 @@ enum ice_tx_tstamp_work {
* @calibrating: if true, the PHY is calibrating the Tx offset. During this
* window, timestamps are temporarily disabled.
* @verify_cached: if true, verify new timestamp differs from last read value
* @last_ll_ts_idx_read: index of the last LL TS read by the FW
*/
struct ice_ptp_tx {
spinlock_t lock; /* lock protecting in_use bitmap */
......@@ -143,6 +144,7 @@ struct ice_ptp_tx {
u8 init : 1;
u8 calibrating : 1;
u8 verify_cached : 1;
s8 last_ll_ts_idx_read;
};
/* Quad and port information for initializing timestamp blocks */
......@@ -296,6 +298,8 @@ void ice_ptp_restore_timestamp_mode(struct ice_pf *pf);
void ice_ptp_extts_event(struct ice_pf *pf);
s8 ice_ptp_request_ts(struct ice_ptp_tx *tx, struct sk_buff *skb);
void ice_ptp_req_tx_single_tstamp(struct ice_ptp_tx *tx, u8 idx);
void ice_ptp_complete_tx_single_tstamp(struct ice_ptp_tx *tx);
enum ice_tx_tstamp_work ice_ptp_process_ts(struct ice_pf *pf);
u64 ice_ptp_get_rx_hwts(const union ice_32b_rx_flex_desc *rx_desc,
......@@ -324,6 +328,11 @@ ice_ptp_request_ts(struct ice_ptp_tx *tx, struct sk_buff *skb)
return -1;
}
static inline void ice_ptp_req_tx_single_tstamp(struct ice_ptp_tx *tx, u8 idx)
{ }
static inline void ice_ptp_complete_tx_single_tstamp(struct ice_ptp_tx *tx) { }
static inline bool ice_ptp_process_ts(struct ice_pf *pf)
{
return true;
......
......@@ -509,6 +509,7 @@ int ice_cgu_get_output_pin_state_caps(struct ice_hw *hw, u8 pin_id,
#define TS_LL_READ_RETRIES 200
#define TS_LL_READ_TS_HIGH GENMASK(23, 16)
#define TS_LL_READ_TS_IDX GENMASK(29, 24)
#define TS_LL_READ_TS_INTR BIT(30)
#define TS_LL_READ_TS BIT(31)
/* Internal PHY timestamp address */
......
......@@ -761,24 +761,6 @@ static void ice_sriov_clear_reset_trigger(struct ice_vf *vf)
ice_flush(hw);
}
/**
* ice_sriov_create_vsi - Create a new VSI for a VF
* @vf: VF to create the VSI for
*
* This is called by ice_vf_recreate_vsi to create the new VSI after the old
* VSI has been released.
*/
static int ice_sriov_create_vsi(struct ice_vf *vf)
{
struct ice_vsi *vsi;
vsi = ice_vf_vsi_setup(vf);
if (!vsi)
return -ENOMEM;
return 0;
}
/**
* ice_sriov_post_vsi_rebuild - tasks to do after the VF's VSI have been rebuilt
* @vf: VF to perform tasks on
......@@ -798,7 +780,6 @@ static const struct ice_vf_ops ice_sriov_vf_ops = {
.poll_reset_status = ice_sriov_poll_reset_status,
.clear_reset_trigger = ice_sriov_clear_reset_trigger,
.irq_close = NULL,
.create_vsi = ice_sriov_create_vsi,
.post_vsi_rebuild = ice_sriov_post_vsi_rebuild,
};
......@@ -1141,8 +1122,7 @@ int ice_sriov_set_msix_vec_count(struct pci_dev *vf_dev, int msix_vec_count)
if (vf->first_vector_idx < 0)
goto unroll;
ice_vf_vsi_release(vf);
if (vf->vf_ops->create_vsi(vf)) {
if (ice_vf_reconfig_vsi(vf)) {
/* Try to rebuild with previous values */
needs_rebuild = true;
goto unroll;
......@@ -1169,7 +1149,7 @@ int ice_sriov_set_msix_vec_count(struct pci_dev *vf_dev, int msix_vec_count)
return -EINVAL;
if (needs_rebuild)
vf->vf_ops->create_vsi(vf);
ice_vf_reconfig_vsi(vf);
ice_ena_vf_mappings(vf);
ice_put_vf(vf);
......
......@@ -6059,6 +6059,7 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
rinfo->sw_act.fltr_act == ICE_FWD_TO_Q ||
rinfo->sw_act.fltr_act == ICE_FWD_TO_QGRP ||
rinfo->sw_act.fltr_act == ICE_DROP_PACKET ||
rinfo->sw_act.fltr_act == ICE_MIRROR_PACKET ||
rinfo->sw_act.fltr_act == ICE_NOP)) {
status = -EIO;
goto free_pkt_profile;
......@@ -6071,9 +6072,11 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
}
if (rinfo->sw_act.fltr_act == ICE_FWD_TO_VSI ||
rinfo->sw_act.fltr_act == ICE_NOP)
rinfo->sw_act.fltr_act == ICE_MIRROR_PACKET ||
rinfo->sw_act.fltr_act == ICE_NOP) {
rinfo->sw_act.fwd_id.hw_vsi_id =
ice_get_hw_vsi_num(hw, vsi_handle);
}
if (rinfo->src_vsi)
rinfo->sw_act.src = ice_get_hw_vsi_num(hw, rinfo->src_vsi);
......@@ -6109,12 +6112,15 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
status = -ENOMEM;
goto free_pkt_profile;
}
if (!rinfo->flags_info.act_valid) {
act |= ICE_SINGLE_ACT_LAN_ENABLE;
act |= ICE_SINGLE_ACT_LB_ENABLE;
} else {
act |= rinfo->flags_info.act & (ICE_SINGLE_ACT_LAN_ENABLE |
ICE_SINGLE_ACT_LB_ENABLE);
if (rinfo->sw_act.fltr_act != ICE_MIRROR_PACKET) {
if (!rinfo->flags_info.act_valid) {
act |= ICE_SINGLE_ACT_LAN_ENABLE;
act |= ICE_SINGLE_ACT_LB_ENABLE;
} else {
act |= rinfo->flags_info.act & (ICE_SINGLE_ACT_LAN_ENABLE |
ICE_SINGLE_ACT_LB_ENABLE);
}
}
switch (rinfo->sw_act.fltr_act) {
......@@ -6140,6 +6146,11 @@ ice_add_adv_rule(struct ice_hw *hw, struct ice_adv_lkup_elem *lkups,
act |= ICE_SINGLE_ACT_VSI_FORWARDING | ICE_SINGLE_ACT_DROP |
ICE_SINGLE_ACT_VALID_BIT;
break;
case ICE_MIRROR_PACKET:
act |= ICE_SINGLE_ACT_OTHER_ACTS;
act |= FIELD_PREP(ICE_SINGLE_ACT_VSI_ID_M,
rinfo->sw_act.fwd_id.hw_vsi_id);
break;
case ICE_NOP:
act |= FIELD_PREP(ICE_SINGLE_ACT_VSI_ID_M,
rinfo->sw_act.fwd_id.hw_vsi_id);
......
......@@ -689,6 +689,41 @@ ice_tc_setup_drop_action(struct net_device *filter_dev,
return 0;
}
static int ice_tc_setup_mirror_action(struct net_device *filter_dev,
struct ice_tc_flower_fltr *fltr,
struct net_device *target_dev)
{
struct ice_repr *repr;
fltr->action.fltr_act = ICE_MIRROR_PACKET;
if (ice_is_port_repr_netdev(filter_dev) &&
ice_is_port_repr_netdev(target_dev)) {
repr = ice_netdev_to_repr(target_dev);
fltr->dest_vsi = repr->src_vsi;
fltr->direction = ICE_ESWITCH_FLTR_EGRESS;
} else if (ice_is_port_repr_netdev(filter_dev) &&
ice_tc_is_dev_uplink(target_dev)) {
repr = ice_netdev_to_repr(filter_dev);
fltr->dest_vsi = repr->src_vsi->back->eswitch.uplink_vsi;
fltr->direction = ICE_ESWITCH_FLTR_EGRESS;
} else if (ice_tc_is_dev_uplink(filter_dev) &&
ice_is_port_repr_netdev(target_dev)) {
repr = ice_netdev_to_repr(target_dev);
fltr->dest_vsi = repr->src_vsi;
fltr->direction = ICE_ESWITCH_FLTR_INGRESS;
} else {
NL_SET_ERR_MSG_MOD(fltr->extack,
"Unsupported netdevice in switchdev mode");
return -EINVAL;
}
return 0;
}
static int ice_eswitch_tc_parse_action(struct net_device *filter_dev,
struct ice_tc_flower_fltr *fltr,
struct flow_action_entry *act)
......@@ -710,6 +745,12 @@ static int ice_eswitch_tc_parse_action(struct net_device *filter_dev,
break;
case FLOW_ACTION_MIRRED:
err = ice_tc_setup_mirror_action(filter_dev, fltr, act->dev);
if (err)
return err;
break;
default:
NL_SET_ERR_MSG_MOD(fltr->extack, "Unsupported action in switchdev mode");
return -EINVAL;
......
......@@ -353,6 +353,7 @@ struct ice_ts_func_info {
#define ICE_TS_TMR0_ENA_M BIT(25)
#define ICE_TS_TMR1_ENA_M BIT(26)
#define ICE_TS_LL_TX_TS_READ_M BIT(28)
#define ICE_TS_LL_TX_TS_INT_READ_M BIT(29)
struct ice_ts_dev_info {
/* Device specific info */
......@@ -366,6 +367,7 @@ struct ice_ts_dev_info {
u8 tmr0_ena;
u8 tmr1_ena;
u8 ts_ll_read;
u8 ts_ll_int_read;
};
/* Function specific capabilities */
......@@ -1001,7 +1003,6 @@ struct ice_hw_port_stats {
u64 error_bytes; /* errbc */
u64 mac_local_faults; /* mlfc */
u64 mac_remote_faults; /* mrfc */
u64 rx_len_errors; /* rlec */
u64 link_xon_rx; /* lxonrxc */
u64 link_xoff_rx; /* lxoffrxc */
u64 link_xon_tx; /* lxontxc */
......@@ -1040,6 +1041,7 @@ enum ice_sw_fwd_act_type {
ICE_FWD_TO_Q,
ICE_FWD_TO_QGRP,
ICE_DROP_PACKET,
ICE_MIRROR_PACKET,
ICE_NOP,
ICE_INVAL_ACT
};
......
......@@ -248,29 +248,44 @@ static void ice_vf_pre_vsi_rebuild(struct ice_vf *vf)
}
/**
* ice_vf_recreate_vsi - Release and re-create the VF's VSI
* @vf: VF to recreate the VSI for
* ice_vf_reconfig_vsi - Reconfigure a VF VSI with the device
* @vf: VF to reconfigure the VSI for
*
* This is only called when a single VF is being reset (i.e. VVF, VFLR, host
* VF configuration change, etc)
* This is called when a single VF is being reset (i.e. VVF, VFLR, host VF
* configuration change, etc).
*
* It releases and then re-creates a new VSI.
* It brings the VSI down and then reconfigures it with the hardware.
*/
static int ice_vf_recreate_vsi(struct ice_vf *vf)
int ice_vf_reconfig_vsi(struct ice_vf *vf)
{
struct ice_vsi *vsi = ice_get_vf_vsi(vf);
struct ice_vsi_cfg_params params = {};
struct ice_pf *pf = vf->pf;
int err;
ice_vf_vsi_release(vf);
if (WARN_ON(!vsi))
return -EINVAL;
params = ice_vsi_to_params(vsi);
params.flags = ICE_VSI_FLAG_NO_INIT;
err = vf->vf_ops->create_vsi(vf);
ice_vsi_decfg(vsi);
ice_fltr_remove_all(vsi);
err = ice_vsi_cfg(vsi, &params);
if (err) {
dev_err(ice_pf_to_dev(pf),
"Failed to recreate the VF%u's VSI, error %d\n",
"Failed to reconfigure the VF%u's VSI, error %d\n",
vf->vf_id, err);
return err;
}
/* Update the lan_vsi_num field since it might have been changed. The
* PF lan_vsi_idx number remains the same so we don't need to change
* that.
*/
vf->lan_vsi_num = vsi->vsi_num;
return 0;
}
......@@ -928,7 +943,7 @@ int ice_reset_vf(struct ice_vf *vf, u32 flags)
ice_vf_pre_vsi_rebuild(vf);
if (ice_vf_recreate_vsi(vf)) {
if (ice_vf_reconfig_vsi(vf)) {
dev_err(dev, "Failed to release and setup the VF%u's VSI\n",
vf->vf_id);
err = -EFAULT;
......
......@@ -62,7 +62,6 @@ struct ice_vf_ops {
bool (*poll_reset_status)(struct ice_vf *vf);
void (*clear_reset_trigger)(struct ice_vf *vf);
void (*irq_close)(struct ice_vf *vf);
int (*create_vsi)(struct ice_vf *vf);
void (*post_vsi_rebuild)(struct ice_vf *vf);
};
......
......@@ -23,6 +23,7 @@
#warning "Only include ice_vf_lib_private.h in CONFIG_PCI_IOV virtualization files"
#endif
int ice_vf_reconfig_vsi(struct ice_vf *vf);
void ice_initialize_vf_entry(struct ice_vf *vf);
void ice_dis_vf_qs(struct ice_vf *vf);
int ice_check_vf_init(struct ice_vf *vf);
......
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