static void fm10k_get_reg_vsi(struct fm10k_hw *hw, u32 *buff, int i) { int idx = 0, j; buff[idx++] = fm10k_read_reg(hw, FM10K_MRQC(i)); for (j = 0; j < 10; j++) buff[idx++] = fm10k_read_reg(hw, FM10K_RSSRK(i, j)); for (j = 0; j < 32; j++) buff[idx++] = fm10k_read_reg(hw, FM10K_RETA(i, j)); BUG_ON(idx != FM10K_REGS_LEN_VSI); }
/** * fm10k_disable_queues_generic - Stop Tx/Rx queues * @hw: pointer to hardware structure * @q_cnt: number of queues to be disabled * **/ s32 fm10k_disable_queues_generic(struct fm10k_hw *hw, u16 q_cnt) { u32 reg; u16 i, time; /* clear tx_ready to prevent any false hits for reset */ hw->mac.tx_ready = false; if (FM10K_REMOVED(hw->hw_addr)) return 0; /* clear the enable bit for all rings */ for (i = 0; i < q_cnt; i++) { reg = fm10k_read_reg(hw, FM10K_TXDCTL(i)); fm10k_write_reg(hw, FM10K_TXDCTL(i), reg & ~FM10K_TXDCTL_ENABLE); reg = fm10k_read_reg(hw, FM10K_RXQCTL(i)); fm10k_write_reg(hw, FM10K_RXQCTL(i), reg & ~FM10K_RXQCTL_ENABLE); } fm10k_write_flush(hw); udelay(1); /* loop through all queues to verify that they are all disabled */ for (i = 0, time = FM10K_QUEUE_DISABLE_TIMEOUT; time;) { /* if we are at end of rings all rings are disabled */ if (i == q_cnt) return 0; /* if queue enables cleared, then move to next ring pair */ reg = fm10k_read_reg(hw, FM10K_TXDCTL(i)); if (!~reg || !(reg & FM10K_TXDCTL_ENABLE)) { reg = fm10k_read_reg(hw, FM10K_RXQCTL(i)); if (!~reg || !(reg & FM10K_RXQCTL_ENABLE)) { i++; continue; } } /* decrement time and wait 1 usec */ time--; if (time) udelay(1); } return FM10K_ERR_REQUESTS_PENDING; }
/** * fm10k_update_hw_stats_rx_q - Updates RX queue statistics counters * @hw: pointer to the hardware structure * @q: pointer to the ring of hardware statistics queue * @idx: index pointing to the start of the ring iteration * * Function updates the RX queue statistics counters that are related to the * hardware. **/ static void fm10k_update_hw_stats_rx_q(struct fm10k_hw *hw, struct fm10k_hw_stats_q *q, u32 idx) { u32 id_rx, id_rx_prev, rx_packets, rx_drops; u64 rx_bytes = 0; /* Retrieve RX Owner Data */ id_rx = fm10k_read_reg(hw, FM10K_RXQCTL(idx)); /* Process RX Ring */ do { rx_drops = fm10k_read_hw_stats_32b(hw, FM10K_QPRDC(idx), &q->rx_drops); rx_packets = fm10k_read_hw_stats_32b(hw, FM10K_QPRC(idx), &q->rx_packets); if (rx_packets) rx_bytes = fm10k_read_hw_stats_48b(hw, FM10K_QBRC_L(idx), &q->rx_bytes); /* Re-Check Owner Data */ id_rx_prev = id_rx; id_rx = fm10k_read_reg(hw, FM10K_RXQCTL(idx)); } while ((id_rx ^ id_rx_prev) & FM10K_RXQCTL_ID_MASK); /* drop non-ID bits and set VALID ID bit */ id_rx &= FM10K_RXQCTL_ID_MASK; id_rx |= FM10K_STAT_VALID; /* update packet counts */ if (q->rx_stats_idx == id_rx) { q->rx_drops.count += rx_drops; q->rx_packets.count += rx_packets; q->rx_bytes.count += rx_bytes; } /* update bases and record ID */ fm10k_update_hw_base_32b(&q->rx_drops, rx_drops); fm10k_update_hw_base_32b(&q->rx_packets, rx_packets); fm10k_update_hw_base_48b(&q->rx_bytes, rx_bytes); q->rx_stats_idx = id_rx; }
/** * fm10k_read_hw_stats_32b - Reads value of 32-bit registers * @hw: pointer to the hardware structure * @addr: address of register containing a 32-bit value * @stat: pointer to structure holding hw stat information * * Function reads the content of the register and returns the delta * between the base and the current value. * **/ u32 fm10k_read_hw_stats_32b(struct fm10k_hw *hw, u32 addr, struct fm10k_hw_stat *stat) { u32 delta = fm10k_read_reg(hw, addr) - stat->base_l; if (FM10K_REMOVED(hw->hw_addr)) stat->base_h = 0; return delta; }
/** * fm10k_update_hw_stats_tx_q - Updates TX queue statistics counters * @hw: pointer to the hardware structure * @q: pointer to the ring of hardware statistics queue * @idx: index pointing to the start of the ring iteration * * Function updates the TX queue statistics counters that are related to the * hardware. **/ static void fm10k_update_hw_stats_tx_q(struct fm10k_hw *hw, struct fm10k_hw_stats_q *q, u32 idx) { u32 id_tx, id_tx_prev, tx_packets; u64 tx_bytes = 0; /* Retrieve TX Owner Data */ id_tx = fm10k_read_reg(hw, FM10K_TXQCTL(idx)); /* Process TX Ring */ do { tx_packets = fm10k_read_hw_stats_32b(hw, FM10K_QPTC(idx), &q->tx_packets); if (tx_packets) tx_bytes = fm10k_read_hw_stats_48b(hw, FM10K_QBTC_L(idx), &q->tx_bytes); /* Re-Check Owner Data */ id_tx_prev = id_tx; id_tx = fm10k_read_reg(hw, FM10K_TXQCTL(idx)); } while ((id_tx ^ id_tx_prev) & FM10K_TXQCTL_ID_MASK); /* drop non-ID bits and set VALID ID bit */ id_tx &= FM10K_TXQCTL_ID_MASK; id_tx |= FM10K_STAT_VALID; /* update packet counts */ if (q->tx_stats_idx == id_tx) { q->tx_packets.count += tx_packets; q->tx_bytes.count += tx_bytes; } /* update bases and record ID */ fm10k_update_hw_base_32b(&q->tx_packets, tx_packets); fm10k_update_hw_base_48b(&q->tx_bytes, tx_bytes); q->tx_stats_idx = id_tx; }
/** * fm10k_read_hw_stats_48b - Reads value of 48-bit registers * @hw: pointer to the hardware structure * @addr: address of register containing the lower 32-bit value * @stat: pointer to structure holding hw stat information * * Function reads the content of 2 registers, combined to represent a 48-bit * statistical value. Extra processing is required to handle overflowing. * Finally, a delta value is returned representing the difference between the * values stored in registers and values stored in the statistic counters. * **/ static u64 fm10k_read_hw_stats_48b(struct fm10k_hw *hw, u32 addr, struct fm10k_hw_stat *stat) { u32 count_l; u32 count_h; u32 count_tmp; u64 delta; count_h = fm10k_read_reg(hw, addr + 1); /* Check for overflow */ do { count_tmp = count_h; count_l = fm10k_read_reg(hw, addr); count_h = fm10k_read_reg(hw, addr + 1); } while (count_h != count_tmp); delta = ((u64)(count_h - stat->base_h) << 32) + count_l; delta -= stat->base_l; return delta & FM10K_48_BIT_MASK; }
/** * fm10k_get_host_state_generic - Returns the state of the host * @hw: pointer to hardware structure * @host_ready: pointer to boolean value that will record host state * * This function will check the health of the mailbox and Tx queue 0 * in order to determine if we should report that the link is up or not. **/ s32 fm10k_get_host_state_generic(struct fm10k_hw *hw, bool *host_ready) { struct fm10k_mbx_info *mbx = &hw->mbx; struct fm10k_mac_info *mac = &hw->mac; s32 ret_val = 0; u32 txdctl = fm10k_read_reg(hw, FM10K_TXDCTL(0)); /* process upstream mailbox in case interrupts were disabled */ mbx->ops.process(hw, mbx); /* If Tx is no longer enabled link should come down */ if (!(~txdctl) || !(txdctl & FM10K_TXDCTL_ENABLE)) mac->get_host_state = true; /* exit if not checking for link, or link cannot be changed */ if (!mac->get_host_state || !(~txdctl)) goto out; /* if we somehow dropped the Tx enable we should reset */ if (mac->tx_ready && !(txdctl & FM10K_TXDCTL_ENABLE)) { ret_val = FM10K_ERR_RESET_REQUESTED; goto out; } /* if Mailbox timed out we should request reset */ if (!mbx->timeout) { ret_val = FM10K_ERR_RESET_REQUESTED; goto out; } /* verify Mailbox is still open */ if (mbx->state != FM10K_STATE_OPEN) goto out; /* interface cannot receive traffic without logical ports */ if (mac->dglort_map == FM10K_DGLORTMAP_NONE) { if (mac->ops.request_lport_map) ret_val = mac->ops.request_lport_map(hw); goto out; } /* if we passed all the tests above then the switch is ready and we no * longer need to check for link */ mac->get_host_state = false; out: *host_ready = !mac->get_host_state; return ret_val; }
static void fm10k_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p) { struct fm10k_intfc *interface = netdev_priv(netdev); struct fm10k_hw *hw = &interface->hw; u32 *buff = p; u16 i; regs->version = (1 << 24) | (hw->revision_id << 16) | hw->device_id; switch (hw->mac.type) { case fm10k_mac_pf: /* General PF Registers */ *(buff++) = fm10k_read_reg(hw, FM10K_CTRL); *(buff++) = fm10k_read_reg(hw, FM10K_CTRL_EXT); *(buff++) = fm10k_read_reg(hw, FM10K_GCR); *(buff++) = fm10k_read_reg(hw, FM10K_GCR_EXT); for (i = 0; i < 8; i++) { *(buff++) = fm10k_read_reg(hw, FM10K_DGLORTMAP(i)); *(buff++) = fm10k_read_reg(hw, FM10K_DGLORTDEC(i)); } for (i = 0; i < 65; i++) { fm10k_get_reg_vsi(hw, buff, i); buff += FM10K_REGS_LEN_VSI; } *(buff++) = fm10k_read_reg(hw, FM10K_DMA_CTRL); *(buff++) = fm10k_read_reg(hw, FM10K_DMA_CTRL2); for (i = 0; i < FM10K_MAX_QUEUES_PF; i++) { fm10k_get_reg_q(hw, buff, i); buff += FM10K_REGS_LEN_Q; } *(buff++) = fm10k_read_reg(hw, FM10K_TPH_CTRL); for (i = 0; i < 8; i++) *(buff++) = fm10k_read_reg(hw, FM10K_INT_MAP(i)); /* Interrupt Throttling Registers */ for (i = 0; i < 130; i++) *(buff++) = fm10k_read_reg(hw, FM10K_ITR(i)); break; case fm10k_mac_vf: /* General VF registers */ *(buff++) = fm10k_read_reg(hw, FM10K_VFCTRL); *(buff++) = fm10k_read_reg(hw, FM10K_VFINT_MAP); *(buff++) = fm10k_read_reg(hw, FM10K_VFSYSTIME); /* Interrupt Throttling Registers */ for (i = 0; i < 8; i++) *(buff++) = fm10k_read_reg(hw, FM10K_VFITR(i)); fm10k_get_reg_vsi(hw, buff, 0); buff += FM10K_REGS_LEN_VSI; for (i = 0; i < FM10K_MAX_QUEUES_POOL; i++) { if (i < hw->mac.max_queues) fm10k_get_reg_q(hw, buff, i); else memset(buff, 0, sizeof(u32) * FM10K_REGS_LEN_Q); buff += FM10K_REGS_LEN_Q; } break; default: return; } }
static void fm10k_get_reg_q(struct fm10k_hw *hw, u32 *buff, int i) { int idx = 0; buff[idx++] = fm10k_read_reg(hw, FM10K_RDBAL(i)); buff[idx++] = fm10k_read_reg(hw, FM10K_RDBAH(i)); buff[idx++] = fm10k_read_reg(hw, FM10K_RDLEN(i)); buff[idx++] = fm10k_read_reg(hw, FM10K_TPH_RXCTRL(i)); buff[idx++] = fm10k_read_reg(hw, FM10K_RDH(i)); buff[idx++] = fm10k_read_reg(hw, FM10K_RDT(i)); buff[idx++] = fm10k_read_reg(hw, FM10K_RXQCTL(i)); buff[idx++] = fm10k_read_reg(hw, FM10K_RXDCTL(i)); buff[idx++] = fm10k_read_reg(hw, FM10K_RXINT(i)); buff[idx++] = fm10k_read_reg(hw, FM10K_SRRCTL(i)); buff[idx++] = fm10k_read_reg(hw, FM10K_QPRC(i)); buff[idx++] = fm10k_read_reg(hw, FM10K_QPRDC(i)); buff[idx++] = fm10k_read_reg(hw, FM10K_QBRC_L(i)); buff[idx++] = fm10k_read_reg(hw, FM10K_QBRC_H(i)); buff[idx++] = fm10k_read_reg(hw, FM10K_TDBAL(i)); buff[idx++] = fm10k_read_reg(hw, FM10K_TDBAH(i)); buff[idx++] = fm10k_read_reg(hw, FM10K_TDLEN(i)); buff[idx++] = fm10k_read_reg(hw, FM10K_TPH_TXCTRL(i)); buff[idx++] = fm10k_read_reg(hw, FM10K_TDH(i)); buff[idx++] = fm10k_read_reg(hw, FM10K_TDT(i)); buff[idx++] = fm10k_read_reg(hw, FM10K_TXDCTL(i)); buff[idx++] = fm10k_read_reg(hw, FM10K_TXQCTL(i)); buff[idx++] = fm10k_read_reg(hw, FM10K_TXINT(i)); buff[idx++] = fm10k_read_reg(hw, FM10K_QPTC(i)); buff[idx++] = fm10k_read_reg(hw, FM10K_QBTC_L(i)); buff[idx++] = fm10k_read_reg(hw, FM10K_QBTC_H(i)); buff[idx++] = fm10k_read_reg(hw, FM10K_TQDLOC(i)); buff[idx++] = fm10k_read_reg(hw, FM10K_TX_SGLORT(i)); buff[idx++] = fm10k_read_reg(hw, FM10K_PFVTCTL(i)); BUG_ON(idx != FM10K_REGS_LEN_Q); }