brintos

brintos / linux-shallow public Read only

0
0
Text · 14.0 KiB · f51a63f Raw
525 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright(c) 2013 - 2018 Intel Corporation. */3 4#include "fm10k_common.h"5 6/**7 *  fm10k_get_bus_info_generic - Generic set PCI bus info8 *  @hw: pointer to hardware structure9 *10 *  Gets the PCI bus info (speed, width, type) then calls helper function to11 *  store this data within the fm10k_hw structure.12 **/13s32 fm10k_get_bus_info_generic(struct fm10k_hw *hw)14{15	u16 link_cap, link_status, device_cap, device_control;16 17	/* Get the maximum link width and speed from PCIe config space */18	link_cap = fm10k_read_pci_cfg_word(hw, FM10K_PCIE_LINK_CAP);19 20	switch (link_cap & FM10K_PCIE_LINK_WIDTH) {21	case FM10K_PCIE_LINK_WIDTH_1:22		hw->bus_caps.width = fm10k_bus_width_pcie_x1;23		break;24	case FM10K_PCIE_LINK_WIDTH_2:25		hw->bus_caps.width = fm10k_bus_width_pcie_x2;26		break;27	case FM10K_PCIE_LINK_WIDTH_4:28		hw->bus_caps.width = fm10k_bus_width_pcie_x4;29		break;30	case FM10K_PCIE_LINK_WIDTH_8:31		hw->bus_caps.width = fm10k_bus_width_pcie_x8;32		break;33	default:34		hw->bus_caps.width = fm10k_bus_width_unknown;35		break;36	}37 38	switch (link_cap & FM10K_PCIE_LINK_SPEED) {39	case FM10K_PCIE_LINK_SPEED_2500:40		hw->bus_caps.speed = fm10k_bus_speed_2500;41		break;42	case FM10K_PCIE_LINK_SPEED_5000:43		hw->bus_caps.speed = fm10k_bus_speed_5000;44		break;45	case FM10K_PCIE_LINK_SPEED_8000:46		hw->bus_caps.speed = fm10k_bus_speed_8000;47		break;48	default:49		hw->bus_caps.speed = fm10k_bus_speed_unknown;50		break;51	}52 53	/* Get the PCIe maximum payload size for the PCIe function */54	device_cap = fm10k_read_pci_cfg_word(hw, FM10K_PCIE_DEV_CAP);55 56	switch (device_cap & FM10K_PCIE_DEV_CAP_PAYLOAD) {57	case FM10K_PCIE_DEV_CAP_PAYLOAD_128:58		hw->bus_caps.payload = fm10k_bus_payload_128;59		break;60	case FM10K_PCIE_DEV_CAP_PAYLOAD_256:61		hw->bus_caps.payload = fm10k_bus_payload_256;62		break;63	case FM10K_PCIE_DEV_CAP_PAYLOAD_512:64		hw->bus_caps.payload = fm10k_bus_payload_512;65		break;66	default:67		hw->bus_caps.payload = fm10k_bus_payload_unknown;68		break;69	}70 71	/* Get the negotiated link width and speed from PCIe config space */72	link_status = fm10k_read_pci_cfg_word(hw, FM10K_PCIE_LINK_STATUS);73 74	switch (link_status & FM10K_PCIE_LINK_WIDTH) {75	case FM10K_PCIE_LINK_WIDTH_1:76		hw->bus.width = fm10k_bus_width_pcie_x1;77		break;78	case FM10K_PCIE_LINK_WIDTH_2:79		hw->bus.width = fm10k_bus_width_pcie_x2;80		break;81	case FM10K_PCIE_LINK_WIDTH_4:82		hw->bus.width = fm10k_bus_width_pcie_x4;83		break;84	case FM10K_PCIE_LINK_WIDTH_8:85		hw->bus.width = fm10k_bus_width_pcie_x8;86		break;87	default:88		hw->bus.width = fm10k_bus_width_unknown;89		break;90	}91 92	switch (link_status & FM10K_PCIE_LINK_SPEED) {93	case FM10K_PCIE_LINK_SPEED_2500:94		hw->bus.speed = fm10k_bus_speed_2500;95		break;96	case FM10K_PCIE_LINK_SPEED_5000:97		hw->bus.speed = fm10k_bus_speed_5000;98		break;99	case FM10K_PCIE_LINK_SPEED_8000:100		hw->bus.speed = fm10k_bus_speed_8000;101		break;102	default:103		hw->bus.speed = fm10k_bus_speed_unknown;104		break;105	}106 107	/* Get the negotiated PCIe maximum payload size for the PCIe function */108	device_control = fm10k_read_pci_cfg_word(hw, FM10K_PCIE_DEV_CTRL);109 110	switch (device_control & FM10K_PCIE_DEV_CTRL_PAYLOAD) {111	case FM10K_PCIE_DEV_CTRL_PAYLOAD_128:112		hw->bus.payload = fm10k_bus_payload_128;113		break;114	case FM10K_PCIE_DEV_CTRL_PAYLOAD_256:115		hw->bus.payload = fm10k_bus_payload_256;116		break;117	case FM10K_PCIE_DEV_CTRL_PAYLOAD_512:118		hw->bus.payload = fm10k_bus_payload_512;119		break;120	default:121		hw->bus.payload = fm10k_bus_payload_unknown;122		break;123	}124 125	return 0;126}127 128static u16 fm10k_get_pcie_msix_count_generic(struct fm10k_hw *hw)129{130	u16 msix_count;131 132	/* read in value from MSI-X capability register */133	msix_count = fm10k_read_pci_cfg_word(hw, FM10K_PCI_MSIX_MSG_CTRL);134	msix_count &= FM10K_PCI_MSIX_MSG_CTRL_TBL_SZ_MASK;135 136	/* MSI-X count is zero-based in HW */137	msix_count++;138 139	if (msix_count > FM10K_MAX_MSIX_VECTORS)140		msix_count = FM10K_MAX_MSIX_VECTORS;141 142	return msix_count;143}144 145/**146 *  fm10k_get_invariants_generic - Inits constant values147 *  @hw: pointer to the hardware structure148 *149 *  Initialize the common invariants for the device.150 **/151s32 fm10k_get_invariants_generic(struct fm10k_hw *hw)152{153	struct fm10k_mac_info *mac = &hw->mac;154 155	/* initialize GLORT state to avoid any false hits */156	mac->dglort_map = FM10K_DGLORTMAP_NONE;157 158	/* record maximum number of MSI-X vectors */159	mac->max_msix_vectors = fm10k_get_pcie_msix_count_generic(hw);160 161	return 0;162}163 164/**165 *  fm10k_start_hw_generic - Prepare hardware for Tx/Rx166 *  @hw: pointer to hardware structure167 *168 *  This function sets the Tx ready flag to indicate that the Tx path has169 *  been initialized.170 **/171s32 fm10k_start_hw_generic(struct fm10k_hw *hw)172{173	/* set flag indicating we are beginning Tx */174	hw->mac.tx_ready = true;175 176	return 0;177}178 179/**180 *  fm10k_disable_queues_generic - Stop Tx/Rx queues181 *  @hw: pointer to hardware structure182 *  @q_cnt: number of queues to be disabled183 *184 **/185s32 fm10k_disable_queues_generic(struct fm10k_hw *hw, u16 q_cnt)186{187	u32 reg;188	u16 i, time;189 190	/* clear tx_ready to prevent any false hits for reset */191	hw->mac.tx_ready = false;192 193	if (FM10K_REMOVED(hw->hw_addr))194		return 0;195 196	/* clear the enable bit for all rings */197	for (i = 0; i < q_cnt; i++) {198		reg = fm10k_read_reg(hw, FM10K_TXDCTL(i));199		fm10k_write_reg(hw, FM10K_TXDCTL(i),200				reg & ~FM10K_TXDCTL_ENABLE);201		reg = fm10k_read_reg(hw, FM10K_RXQCTL(i));202		fm10k_write_reg(hw, FM10K_RXQCTL(i),203				reg & ~FM10K_RXQCTL_ENABLE);204	}205 206	fm10k_write_flush(hw);207	udelay(1);208 209	/* loop through all queues to verify that they are all disabled */210	for (i = 0, time = FM10K_QUEUE_DISABLE_TIMEOUT; time;) {211		/* if we are at end of rings all rings are disabled */212		if (i == q_cnt)213			return 0;214 215		/* if queue enables cleared, then move to next ring pair */216		reg = fm10k_read_reg(hw, FM10K_TXDCTL(i));217		if (!~reg || !(reg & FM10K_TXDCTL_ENABLE)) {218			reg = fm10k_read_reg(hw, FM10K_RXQCTL(i));219			if (!~reg || !(reg & FM10K_RXQCTL_ENABLE)) {220				i++;221				continue;222			}223		}224 225		/* decrement time and wait 1 usec */226		time--;227		if (time)228			udelay(1);229	}230 231	return FM10K_ERR_REQUESTS_PENDING;232}233 234/**235 *  fm10k_stop_hw_generic - Stop Tx/Rx units236 *  @hw: pointer to hardware structure237 *238 **/239s32 fm10k_stop_hw_generic(struct fm10k_hw *hw)240{241	return fm10k_disable_queues_generic(hw, hw->mac.max_queues);242}243 244/**245 *  fm10k_read_hw_stats_32b - Reads value of 32-bit registers246 *  @hw: pointer to the hardware structure247 *  @addr: address of register containing a 32-bit value248 *  @stat: pointer to structure holding hw stat information249 *250 *  Function reads the content of the register and returns the delta251 *  between the base and the current value.252 *  **/253u32 fm10k_read_hw_stats_32b(struct fm10k_hw *hw, u32 addr,254			    struct fm10k_hw_stat *stat)255{256	u32 delta = fm10k_read_reg(hw, addr) - stat->base_l;257 258	if (FM10K_REMOVED(hw->hw_addr))259		stat->base_h = 0;260 261	return delta;262}263 264/**265 *  fm10k_read_hw_stats_48b - Reads value of 48-bit registers266 *  @hw: pointer to the hardware structure267 *  @addr: address of register containing the lower 32-bit value268 *  @stat: pointer to structure holding hw stat information269 *270 *  Function reads the content of 2 registers, combined to represent a 48-bit271 *  statistical value. Extra processing is required to handle overflowing.272 *  Finally, a delta value is returned representing the difference between the273 *  values stored in registers and values stored in the statistic counters.274 *  **/275static u64 fm10k_read_hw_stats_48b(struct fm10k_hw *hw, u32 addr,276				   struct fm10k_hw_stat *stat)277{278	u32 count_l;279	u32 count_h;280	u32 count_tmp;281	u64 delta;282 283	count_h = fm10k_read_reg(hw, addr + 1);284 285	/* Check for overflow */286	do {287		count_tmp = count_h;288		count_l = fm10k_read_reg(hw, addr);289		count_h = fm10k_read_reg(hw, addr + 1);290	} while (count_h != count_tmp);291 292	delta = ((u64)(count_h - stat->base_h) << 32) + count_l;293	delta -= stat->base_l;294 295	return delta & FM10K_48_BIT_MASK;296}297 298/**299 *  fm10k_update_hw_base_48b - Updates 48-bit statistic base value300 *  @stat: pointer to the hardware statistic structure301 *  @delta: value to be updated into the hardware statistic structure302 *303 *  Function receives a value and determines if an update is required based on304 *  a delta calculation. Only the base value will be updated.305 **/306static void fm10k_update_hw_base_48b(struct fm10k_hw_stat *stat, u64 delta)307{308	if (!delta)309		return;310 311	/* update lower 32 bits */312	delta += stat->base_l;313	stat->base_l = (u32)delta;314 315	/* update upper 32 bits */316	stat->base_h += (u32)(delta >> 32);317}318 319/**320 *  fm10k_update_hw_stats_tx_q - Updates TX queue statistics counters321 *  @hw: pointer to the hardware structure322 *  @q: pointer to the ring of hardware statistics queue323 *  @idx: index pointing to the start of the ring iteration324 *325 *  Function updates the TX queue statistics counters that are related to the326 *  hardware.327 **/328static void fm10k_update_hw_stats_tx_q(struct fm10k_hw *hw,329				       struct fm10k_hw_stats_q *q,330				       u32 idx)331{332	u32 id_tx, id_tx_prev, tx_packets;333	u64 tx_bytes = 0;334 335	/* Retrieve TX Owner Data */336	id_tx = fm10k_read_reg(hw, FM10K_TXQCTL(idx));337 338	/* Process TX Ring */339	do {340		tx_packets = fm10k_read_hw_stats_32b(hw, FM10K_QPTC(idx),341						     &q->tx_packets);342 343		if (tx_packets)344			tx_bytes = fm10k_read_hw_stats_48b(hw,345							   FM10K_QBTC_L(idx),346							   &q->tx_bytes);347 348		/* Re-Check Owner Data */349		id_tx_prev = id_tx;350		id_tx = fm10k_read_reg(hw, FM10K_TXQCTL(idx));351	} while ((id_tx ^ id_tx_prev) & FM10K_TXQCTL_ID_MASK);352 353	/* drop non-ID bits and set VALID ID bit */354	id_tx &= FM10K_TXQCTL_ID_MASK;355	id_tx |= FM10K_STAT_VALID;356 357	/* update packet counts */358	if (q->tx_stats_idx == id_tx) {359		q->tx_packets.count += tx_packets;360		q->tx_bytes.count += tx_bytes;361	}362 363	/* update bases and record ID */364	fm10k_update_hw_base_32b(&q->tx_packets, tx_packets);365	fm10k_update_hw_base_48b(&q->tx_bytes, tx_bytes);366 367	q->tx_stats_idx = id_tx;368}369 370/**371 *  fm10k_update_hw_stats_rx_q - Updates RX queue statistics counters372 *  @hw: pointer to the hardware structure373 *  @q: pointer to the ring of hardware statistics queue374 *  @idx: index pointing to the start of the ring iteration375 *376 *  Function updates the RX queue statistics counters that are related to the377 *  hardware.378 **/379static void fm10k_update_hw_stats_rx_q(struct fm10k_hw *hw,380				       struct fm10k_hw_stats_q *q,381				       u32 idx)382{383	u32 id_rx, id_rx_prev, rx_packets, rx_drops;384	u64 rx_bytes = 0;385 386	/* Retrieve RX Owner Data */387	id_rx = fm10k_read_reg(hw, FM10K_RXQCTL(idx));388 389	/* Process RX Ring */390	do {391		rx_drops = fm10k_read_hw_stats_32b(hw, FM10K_QPRDC(idx),392						   &q->rx_drops);393 394		rx_packets = fm10k_read_hw_stats_32b(hw, FM10K_QPRC(idx),395						     &q->rx_packets);396 397		if (rx_packets)398			rx_bytes = fm10k_read_hw_stats_48b(hw,399							   FM10K_QBRC_L(idx),400							   &q->rx_bytes);401 402		/* Re-Check Owner Data */403		id_rx_prev = id_rx;404		id_rx = fm10k_read_reg(hw, FM10K_RXQCTL(idx));405	} while ((id_rx ^ id_rx_prev) & FM10K_RXQCTL_ID_MASK);406 407	/* drop non-ID bits and set VALID ID bit */408	id_rx &= FM10K_RXQCTL_ID_MASK;409	id_rx |= FM10K_STAT_VALID;410 411	/* update packet counts */412	if (q->rx_stats_idx == id_rx) {413		q->rx_drops.count += rx_drops;414		q->rx_packets.count += rx_packets;415		q->rx_bytes.count += rx_bytes;416	}417 418	/* update bases and record ID */419	fm10k_update_hw_base_32b(&q->rx_drops, rx_drops);420	fm10k_update_hw_base_32b(&q->rx_packets, rx_packets);421	fm10k_update_hw_base_48b(&q->rx_bytes, rx_bytes);422 423	q->rx_stats_idx = id_rx;424}425 426/**427 *  fm10k_update_hw_stats_q - Updates queue statistics counters428 *  @hw: pointer to the hardware structure429 *  @q: pointer to the ring of hardware statistics queue430 *  @idx: index pointing to the start of the ring iteration431 *  @count: number of queues to iterate over432 *433 *  Function updates the queue statistics counters that are related to the434 *  hardware.435 **/436void fm10k_update_hw_stats_q(struct fm10k_hw *hw, struct fm10k_hw_stats_q *q,437			     u32 idx, u32 count)438{439	u32 i;440 441	for (i = 0; i < count; i++, idx++, q++) {442		fm10k_update_hw_stats_tx_q(hw, q, idx);443		fm10k_update_hw_stats_rx_q(hw, q, idx);444	}445}446 447/**448 *  fm10k_unbind_hw_stats_q - Unbind the queue counters from their queues449 *  @q: pointer to the ring of hardware statistics queue450 *  @idx: index pointing to the start of the ring iteration451 *  @count: number of queues to iterate over452 *453 *  Function invalidates the index values for the queues so any updates that454 *  may have happened are ignored and the base for the queue stats is reset.455 **/456void fm10k_unbind_hw_stats_q(struct fm10k_hw_stats_q *q, u32 idx, u32 count)457{458	u32 i;459 460	for (i = 0; i < count; i++, idx++, q++) {461		q->rx_stats_idx = 0;462		q->tx_stats_idx = 0;463	}464}465 466/**467 *  fm10k_get_host_state_generic - Returns the state of the host468 *  @hw: pointer to hardware structure469 *  @host_ready: pointer to boolean value that will record host state470 *471 *  This function will check the health of the mailbox and Tx queue 0472 *  in order to determine if we should report that the link is up or not.473 **/474s32 fm10k_get_host_state_generic(struct fm10k_hw *hw, bool *host_ready)475{476	struct fm10k_mbx_info *mbx = &hw->mbx;477	struct fm10k_mac_info *mac = &hw->mac;478	s32 ret_val = 0;479	u32 txdctl = fm10k_read_reg(hw, FM10K_TXDCTL(0));480 481	/* process upstream mailbox in case interrupts were disabled */482	mbx->ops.process(hw, mbx);483 484	/* If Tx is no longer enabled link should come down */485	if (!(~txdctl) || !(txdctl & FM10K_TXDCTL_ENABLE))486		mac->get_host_state = true;487 488	/* exit if not checking for link, or link cannot be changed */489	if (!mac->get_host_state || !(~txdctl))490		goto out;491 492	/* if we somehow dropped the Tx enable we should reset */493	if (mac->tx_ready && !(txdctl & FM10K_TXDCTL_ENABLE)) {494		ret_val = FM10K_ERR_RESET_REQUESTED;495		goto out;496	}497 498	/* if Mailbox timed out we should request reset */499	if (!mbx->timeout) {500		ret_val = FM10K_ERR_RESET_REQUESTED;501		goto out;502	}503 504	/* verify Mailbox is still open */505	if (mbx->state != FM10K_STATE_OPEN)506		goto out;507 508	/* interface cannot receive traffic without logical ports */509	if (mac->dglort_map == FM10K_DGLORTMAP_NONE) {510		if (mac->ops.request_lport_map)511			ret_val = mac->ops.request_lport_map(hw);512 513		goto out;514	}515 516	/* if we passed all the tests above then the switch is ready and we no517	 * longer need to check for link518	 */519	mac->get_host_state = false;520 521out:522	*host_ready = !mac->get_host_state;523	return ret_val;524}525