162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright (c) 2015 - 2022 Beijing WangXun Technology Co., Ltd. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/etherdevice.h>
562306a36Sopenharmony_ci#include <linux/netdevice.h>
662306a36Sopenharmony_ci#include <linux/if_ether.h>
762306a36Sopenharmony_ci#include <linux/if_vlan.h>
862306a36Sopenharmony_ci#include <linux/iopoll.h>
962306a36Sopenharmony_ci#include <linux/pci.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include "wx_type.h"
1262306a36Sopenharmony_ci#include "wx_lib.h"
1362306a36Sopenharmony_ci#include "wx_hw.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistatic void wx_intr_disable(struct wx *wx, u64 qmask)
1662306a36Sopenharmony_ci{
1762306a36Sopenharmony_ci	u32 mask;
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci	mask = (qmask & U32_MAX);
2062306a36Sopenharmony_ci	if (mask)
2162306a36Sopenharmony_ci		wr32(wx, WX_PX_IMS(0), mask);
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci	if (wx->mac.type == wx_mac_sp) {
2462306a36Sopenharmony_ci		mask = (qmask >> 32);
2562306a36Sopenharmony_ci		if (mask)
2662306a36Sopenharmony_ci			wr32(wx, WX_PX_IMS(1), mask);
2762306a36Sopenharmony_ci	}
2862306a36Sopenharmony_ci}
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_civoid wx_intr_enable(struct wx *wx, u64 qmask)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	u32 mask;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	mask = (qmask & U32_MAX);
3562306a36Sopenharmony_ci	if (mask)
3662306a36Sopenharmony_ci		wr32(wx, WX_PX_IMC(0), mask);
3762306a36Sopenharmony_ci	if (wx->mac.type == wx_mac_sp) {
3862306a36Sopenharmony_ci		mask = (qmask >> 32);
3962306a36Sopenharmony_ci		if (mask)
4062306a36Sopenharmony_ci			wr32(wx, WX_PX_IMC(1), mask);
4162306a36Sopenharmony_ci	}
4262306a36Sopenharmony_ci}
4362306a36Sopenharmony_ciEXPORT_SYMBOL(wx_intr_enable);
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci/**
4662306a36Sopenharmony_ci * wx_irq_disable - Mask off interrupt generation on the NIC
4762306a36Sopenharmony_ci * @wx: board private structure
4862306a36Sopenharmony_ci **/
4962306a36Sopenharmony_civoid wx_irq_disable(struct wx *wx)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	struct pci_dev *pdev = wx->pdev;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	wr32(wx, WX_PX_MISC_IEN, 0);
5462306a36Sopenharmony_ci	wx_intr_disable(wx, WX_INTR_ALL);
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	if (pdev->msix_enabled) {
5762306a36Sopenharmony_ci		int vector;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci		for (vector = 0; vector < wx->num_q_vectors; vector++)
6062306a36Sopenharmony_ci			synchronize_irq(wx->msix_entries[vector].vector);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci		synchronize_irq(wx->msix_entries[vector].vector);
6362306a36Sopenharmony_ci	} else {
6462306a36Sopenharmony_ci		synchronize_irq(pdev->irq);
6562306a36Sopenharmony_ci	}
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ciEXPORT_SYMBOL(wx_irq_disable);
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci/* cmd_addr is used for some special command:
7062306a36Sopenharmony_ci * 1. to be sector address, when implemented erase sector command
7162306a36Sopenharmony_ci * 2. to be flash address when implemented read, write flash address
7262306a36Sopenharmony_ci */
7362306a36Sopenharmony_cistatic int wx_fmgr_cmd_op(struct wx *wx, u32 cmd, u32 cmd_addr)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	u32 cmd_val = 0, val = 0;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	cmd_val = WX_SPI_CMD_CMD(cmd) |
7862306a36Sopenharmony_ci		  WX_SPI_CMD_CLK(WX_SPI_CLK_DIV) |
7962306a36Sopenharmony_ci		  cmd_addr;
8062306a36Sopenharmony_ci	wr32(wx, WX_SPI_CMD, cmd_val);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	return read_poll_timeout(rd32, val, (val & 0x1), 10, 100000,
8362306a36Sopenharmony_ci				 false, wx, WX_SPI_STATUS);
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistatic int wx_flash_read_dword(struct wx *wx, u32 addr, u32 *data)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	int ret = 0;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	ret = wx_fmgr_cmd_op(wx, WX_SPI_CMD_READ_DWORD, addr);
9162306a36Sopenharmony_ci	if (ret < 0)
9262306a36Sopenharmony_ci		return ret;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	*data = rd32(wx, WX_SPI_DATA);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	return ret;
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ciint wx_check_flash_load(struct wx *hw, u32 check_bit)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	u32 reg = 0;
10262306a36Sopenharmony_ci	int err = 0;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	/* if there's flash existing */
10562306a36Sopenharmony_ci	if (!(rd32(hw, WX_SPI_STATUS) &
10662306a36Sopenharmony_ci	      WX_SPI_STATUS_FLASH_BYPASS)) {
10762306a36Sopenharmony_ci		/* wait hw load flash done */
10862306a36Sopenharmony_ci		err = read_poll_timeout(rd32, reg, !(reg & check_bit), 20000, 2000000,
10962306a36Sopenharmony_ci					false, hw, WX_SPI_ILDR_STATUS);
11062306a36Sopenharmony_ci		if (err < 0)
11162306a36Sopenharmony_ci			wx_err(hw, "Check flash load timeout.\n");
11262306a36Sopenharmony_ci	}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	return err;
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_ciEXPORT_SYMBOL(wx_check_flash_load);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_civoid wx_control_hw(struct wx *wx, bool drv)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	/* True : Let firmware know the driver has taken over
12162306a36Sopenharmony_ci	 * False : Let firmware take over control of hw
12262306a36Sopenharmony_ci	 */
12362306a36Sopenharmony_ci	wr32m(wx, WX_CFG_PORT_CTL, WX_CFG_PORT_CTL_DRV_LOAD,
12462306a36Sopenharmony_ci	      drv ? WX_CFG_PORT_CTL_DRV_LOAD : 0);
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ciEXPORT_SYMBOL(wx_control_hw);
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci/**
12962306a36Sopenharmony_ci * wx_mng_present - returns 0 when management capability is present
13062306a36Sopenharmony_ci * @wx: pointer to hardware structure
13162306a36Sopenharmony_ci */
13262306a36Sopenharmony_ciint wx_mng_present(struct wx *wx)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	u32 fwsm;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	fwsm = rd32(wx, WX_MIS_ST);
13762306a36Sopenharmony_ci	if (fwsm & WX_MIS_ST_MNG_INIT_DN)
13862306a36Sopenharmony_ci		return 0;
13962306a36Sopenharmony_ci	else
14062306a36Sopenharmony_ci		return -EACCES;
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ciEXPORT_SYMBOL(wx_mng_present);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci/* Software lock to be held while software semaphore is being accessed. */
14562306a36Sopenharmony_cistatic DEFINE_MUTEX(wx_sw_sync_lock);
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci/**
14862306a36Sopenharmony_ci *  wx_release_sw_sync - Release SW semaphore
14962306a36Sopenharmony_ci *  @wx: pointer to hardware structure
15062306a36Sopenharmony_ci *  @mask: Mask to specify which semaphore to release
15162306a36Sopenharmony_ci *
15262306a36Sopenharmony_ci *  Releases the SW semaphore for the specified
15362306a36Sopenharmony_ci *  function (CSR, PHY0, PHY1, EEPROM, Flash)
15462306a36Sopenharmony_ci **/
15562306a36Sopenharmony_cistatic void wx_release_sw_sync(struct wx *wx, u32 mask)
15662306a36Sopenharmony_ci{
15762306a36Sopenharmony_ci	mutex_lock(&wx_sw_sync_lock);
15862306a36Sopenharmony_ci	wr32m(wx, WX_MNG_SWFW_SYNC, mask, 0);
15962306a36Sopenharmony_ci	mutex_unlock(&wx_sw_sync_lock);
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci/**
16362306a36Sopenharmony_ci *  wx_acquire_sw_sync - Acquire SW semaphore
16462306a36Sopenharmony_ci *  @wx: pointer to hardware structure
16562306a36Sopenharmony_ci *  @mask: Mask to specify which semaphore to acquire
16662306a36Sopenharmony_ci *
16762306a36Sopenharmony_ci *  Acquires the SW semaphore for the specified
16862306a36Sopenharmony_ci *  function (CSR, PHY0, PHY1, EEPROM, Flash)
16962306a36Sopenharmony_ci **/
17062306a36Sopenharmony_cistatic int wx_acquire_sw_sync(struct wx *wx, u32 mask)
17162306a36Sopenharmony_ci{
17262306a36Sopenharmony_ci	u32 sem = 0;
17362306a36Sopenharmony_ci	int ret = 0;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	mutex_lock(&wx_sw_sync_lock);
17662306a36Sopenharmony_ci	ret = read_poll_timeout(rd32, sem, !(sem & mask),
17762306a36Sopenharmony_ci				5000, 2000000, false, wx, WX_MNG_SWFW_SYNC);
17862306a36Sopenharmony_ci	if (!ret) {
17962306a36Sopenharmony_ci		sem |= mask;
18062306a36Sopenharmony_ci		wr32(wx, WX_MNG_SWFW_SYNC, sem);
18162306a36Sopenharmony_ci	} else {
18262306a36Sopenharmony_ci		wx_err(wx, "SW Semaphore not granted: 0x%x.\n", sem);
18362306a36Sopenharmony_ci	}
18462306a36Sopenharmony_ci	mutex_unlock(&wx_sw_sync_lock);
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	return ret;
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci/**
19062306a36Sopenharmony_ci *  wx_host_interface_command - Issue command to manageability block
19162306a36Sopenharmony_ci *  @wx: pointer to the HW structure
19262306a36Sopenharmony_ci *  @buffer: contains the command to write and where the return status will
19362306a36Sopenharmony_ci *   be placed
19462306a36Sopenharmony_ci *  @length: length of buffer, must be multiple of 4 bytes
19562306a36Sopenharmony_ci *  @timeout: time in ms to wait for command completion
19662306a36Sopenharmony_ci *  @return_data: read and return data from the buffer (true) or not (false)
19762306a36Sopenharmony_ci *   Needed because FW structures are big endian and decoding of
19862306a36Sopenharmony_ci *   these fields can be 8 bit or 16 bit based on command. Decoding
19962306a36Sopenharmony_ci *   is not easily understood without making a table of commands.
20062306a36Sopenharmony_ci *   So we will leave this up to the caller to read back the data
20162306a36Sopenharmony_ci *   in these cases.
20262306a36Sopenharmony_ci **/
20362306a36Sopenharmony_ciint wx_host_interface_command(struct wx *wx, u32 *buffer,
20462306a36Sopenharmony_ci			      u32 length, u32 timeout, bool return_data)
20562306a36Sopenharmony_ci{
20662306a36Sopenharmony_ci	u32 hdr_size = sizeof(struct wx_hic_hdr);
20762306a36Sopenharmony_ci	u32 hicr, i, bi, buf[64] = {};
20862306a36Sopenharmony_ci	int status = 0;
20962306a36Sopenharmony_ci	u32 dword_len;
21062306a36Sopenharmony_ci	u16 buf_len;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	if (length == 0 || length > WX_HI_MAX_BLOCK_BYTE_LENGTH) {
21362306a36Sopenharmony_ci		wx_err(wx, "Buffer length failure buffersize=%d.\n", length);
21462306a36Sopenharmony_ci		return -EINVAL;
21562306a36Sopenharmony_ci	}
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	status = wx_acquire_sw_sync(wx, WX_MNG_SWFW_SYNC_SW_MB);
21862306a36Sopenharmony_ci	if (status != 0)
21962306a36Sopenharmony_ci		return status;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	/* Calculate length in DWORDs. We must be DWORD aligned */
22262306a36Sopenharmony_ci	if ((length % (sizeof(u32))) != 0) {
22362306a36Sopenharmony_ci		wx_err(wx, "Buffer length failure, not aligned to dword");
22462306a36Sopenharmony_ci		status = -EINVAL;
22562306a36Sopenharmony_ci		goto rel_out;
22662306a36Sopenharmony_ci	}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	dword_len = length >> 2;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	/* The device driver writes the relevant command block
23162306a36Sopenharmony_ci	 * into the ram area.
23262306a36Sopenharmony_ci	 */
23362306a36Sopenharmony_ci	for (i = 0; i < dword_len; i++) {
23462306a36Sopenharmony_ci		wr32a(wx, WX_MNG_MBOX, i, (__force u32)cpu_to_le32(buffer[i]));
23562306a36Sopenharmony_ci		/* write flush */
23662306a36Sopenharmony_ci		buf[i] = rd32a(wx, WX_MNG_MBOX, i);
23762306a36Sopenharmony_ci	}
23862306a36Sopenharmony_ci	/* Setting this bit tells the ARC that a new command is pending. */
23962306a36Sopenharmony_ci	wr32m(wx, WX_MNG_MBOX_CTL,
24062306a36Sopenharmony_ci	      WX_MNG_MBOX_CTL_SWRDY, WX_MNG_MBOX_CTL_SWRDY);
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	status = read_poll_timeout(rd32, hicr, hicr & WX_MNG_MBOX_CTL_FWRDY, 1000,
24362306a36Sopenharmony_ci				   timeout * 1000, false, wx, WX_MNG_MBOX_CTL);
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	/* Check command completion */
24662306a36Sopenharmony_ci	if (status) {
24762306a36Sopenharmony_ci		wx_dbg(wx, "Command has failed with no status valid.\n");
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci		buf[0] = rd32(wx, WX_MNG_MBOX);
25062306a36Sopenharmony_ci		if ((buffer[0] & 0xff) != (~buf[0] >> 24)) {
25162306a36Sopenharmony_ci			status = -EINVAL;
25262306a36Sopenharmony_ci			goto rel_out;
25362306a36Sopenharmony_ci		}
25462306a36Sopenharmony_ci		if ((buf[0] & 0xff0000) >> 16 == 0x80) {
25562306a36Sopenharmony_ci			wx_dbg(wx, "It's unknown cmd.\n");
25662306a36Sopenharmony_ci			status = -EINVAL;
25762306a36Sopenharmony_ci			goto rel_out;
25862306a36Sopenharmony_ci		}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci		wx_dbg(wx, "write value:\n");
26162306a36Sopenharmony_ci		for (i = 0; i < dword_len; i++)
26262306a36Sopenharmony_ci			wx_dbg(wx, "%x ", buffer[i]);
26362306a36Sopenharmony_ci		wx_dbg(wx, "read value:\n");
26462306a36Sopenharmony_ci		for (i = 0; i < dword_len; i++)
26562306a36Sopenharmony_ci			wx_dbg(wx, "%x ", buf[i]);
26662306a36Sopenharmony_ci	}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	if (!return_data)
26962306a36Sopenharmony_ci		goto rel_out;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	/* Calculate length in DWORDs */
27262306a36Sopenharmony_ci	dword_len = hdr_size >> 2;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	/* first pull in the header so we know the buffer length */
27562306a36Sopenharmony_ci	for (bi = 0; bi < dword_len; bi++) {
27662306a36Sopenharmony_ci		buffer[bi] = rd32a(wx, WX_MNG_MBOX, bi);
27762306a36Sopenharmony_ci		le32_to_cpus(&buffer[bi]);
27862306a36Sopenharmony_ci	}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	/* If there is any thing in data position pull it in */
28162306a36Sopenharmony_ci	buf_len = ((struct wx_hic_hdr *)buffer)->buf_len;
28262306a36Sopenharmony_ci	if (buf_len == 0)
28362306a36Sopenharmony_ci		goto rel_out;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	if (length < buf_len + hdr_size) {
28662306a36Sopenharmony_ci		wx_err(wx, "Buffer not large enough for reply message.\n");
28762306a36Sopenharmony_ci		status = -EFAULT;
28862306a36Sopenharmony_ci		goto rel_out;
28962306a36Sopenharmony_ci	}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	/* Calculate length in DWORDs, add 3 for odd lengths */
29262306a36Sopenharmony_ci	dword_len = (buf_len + 3) >> 2;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	/* Pull in the rest of the buffer (bi is where we left off) */
29562306a36Sopenharmony_ci	for (; bi <= dword_len; bi++) {
29662306a36Sopenharmony_ci		buffer[bi] = rd32a(wx, WX_MNG_MBOX, bi);
29762306a36Sopenharmony_ci		le32_to_cpus(&buffer[bi]);
29862306a36Sopenharmony_ci	}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_cirel_out:
30162306a36Sopenharmony_ci	wx_release_sw_sync(wx, WX_MNG_SWFW_SYNC_SW_MB);
30262306a36Sopenharmony_ci	return status;
30362306a36Sopenharmony_ci}
30462306a36Sopenharmony_ciEXPORT_SYMBOL(wx_host_interface_command);
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci/**
30762306a36Sopenharmony_ci *  wx_read_ee_hostif_data - Read EEPROM word using a host interface cmd
30862306a36Sopenharmony_ci *  assuming that the semaphore is already obtained.
30962306a36Sopenharmony_ci *  @wx: pointer to hardware structure
31062306a36Sopenharmony_ci *  @offset: offset of  word in the EEPROM to read
31162306a36Sopenharmony_ci *  @data: word read from the EEPROM
31262306a36Sopenharmony_ci *
31362306a36Sopenharmony_ci *  Reads a 16 bit word from the EEPROM using the hostif.
31462306a36Sopenharmony_ci **/
31562306a36Sopenharmony_cistatic int wx_read_ee_hostif_data(struct wx *wx, u16 offset, u16 *data)
31662306a36Sopenharmony_ci{
31762306a36Sopenharmony_ci	struct wx_hic_read_shadow_ram buffer;
31862306a36Sopenharmony_ci	int status;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	buffer.hdr.req.cmd = FW_READ_SHADOW_RAM_CMD;
32162306a36Sopenharmony_ci	buffer.hdr.req.buf_lenh = 0;
32262306a36Sopenharmony_ci	buffer.hdr.req.buf_lenl = FW_READ_SHADOW_RAM_LEN;
32362306a36Sopenharmony_ci	buffer.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	/* convert offset from words to bytes */
32662306a36Sopenharmony_ci	buffer.address = (__force u32)cpu_to_be32(offset * 2);
32762306a36Sopenharmony_ci	/* one word */
32862306a36Sopenharmony_ci	buffer.length = (__force u16)cpu_to_be16(sizeof(u16));
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	status = wx_host_interface_command(wx, (u32 *)&buffer, sizeof(buffer),
33162306a36Sopenharmony_ci					   WX_HI_COMMAND_TIMEOUT, false);
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	if (status != 0)
33462306a36Sopenharmony_ci		return status;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	*data = (u16)rd32a(wx, WX_MNG_MBOX, FW_NVM_DATA_OFFSET);
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	return status;
33962306a36Sopenharmony_ci}
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci/**
34262306a36Sopenharmony_ci *  wx_read_ee_hostif - Read EEPROM word using a host interface cmd
34362306a36Sopenharmony_ci *  @wx: pointer to hardware structure
34462306a36Sopenharmony_ci *  @offset: offset of  word in the EEPROM to read
34562306a36Sopenharmony_ci *  @data: word read from the EEPROM
34662306a36Sopenharmony_ci *
34762306a36Sopenharmony_ci *  Reads a 16 bit word from the EEPROM using the hostif.
34862306a36Sopenharmony_ci **/
34962306a36Sopenharmony_ciint wx_read_ee_hostif(struct wx *wx, u16 offset, u16 *data)
35062306a36Sopenharmony_ci{
35162306a36Sopenharmony_ci	int status = 0;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	status = wx_acquire_sw_sync(wx, WX_MNG_SWFW_SYNC_SW_FLASH);
35462306a36Sopenharmony_ci	if (status == 0) {
35562306a36Sopenharmony_ci		status = wx_read_ee_hostif_data(wx, offset, data);
35662306a36Sopenharmony_ci		wx_release_sw_sync(wx, WX_MNG_SWFW_SYNC_SW_FLASH);
35762306a36Sopenharmony_ci	}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	return status;
36062306a36Sopenharmony_ci}
36162306a36Sopenharmony_ciEXPORT_SYMBOL(wx_read_ee_hostif);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci/**
36462306a36Sopenharmony_ci *  wx_read_ee_hostif_buffer- Read EEPROM word(s) using hostif
36562306a36Sopenharmony_ci *  @wx: pointer to hardware structure
36662306a36Sopenharmony_ci *  @offset: offset of  word in the EEPROM to read
36762306a36Sopenharmony_ci *  @words: number of words
36862306a36Sopenharmony_ci *  @data: word(s) read from the EEPROM
36962306a36Sopenharmony_ci *
37062306a36Sopenharmony_ci *  Reads a 16 bit word(s) from the EEPROM using the hostif.
37162306a36Sopenharmony_ci **/
37262306a36Sopenharmony_ciint wx_read_ee_hostif_buffer(struct wx *wx,
37362306a36Sopenharmony_ci			     u16 offset, u16 words, u16 *data)
37462306a36Sopenharmony_ci{
37562306a36Sopenharmony_ci	struct wx_hic_read_shadow_ram buffer;
37662306a36Sopenharmony_ci	u32 current_word = 0;
37762306a36Sopenharmony_ci	u16 words_to_read;
37862306a36Sopenharmony_ci	u32 value = 0;
37962306a36Sopenharmony_ci	int status;
38062306a36Sopenharmony_ci	u32 i;
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	/* Take semaphore for the entire operation. */
38362306a36Sopenharmony_ci	status = wx_acquire_sw_sync(wx, WX_MNG_SWFW_SYNC_SW_FLASH);
38462306a36Sopenharmony_ci	if (status != 0)
38562306a36Sopenharmony_ci		return status;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	while (words) {
38862306a36Sopenharmony_ci		if (words > FW_MAX_READ_BUFFER_SIZE / 2)
38962306a36Sopenharmony_ci			words_to_read = FW_MAX_READ_BUFFER_SIZE / 2;
39062306a36Sopenharmony_ci		else
39162306a36Sopenharmony_ci			words_to_read = words;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci		buffer.hdr.req.cmd = FW_READ_SHADOW_RAM_CMD;
39462306a36Sopenharmony_ci		buffer.hdr.req.buf_lenh = 0;
39562306a36Sopenharmony_ci		buffer.hdr.req.buf_lenl = FW_READ_SHADOW_RAM_LEN;
39662306a36Sopenharmony_ci		buffer.hdr.req.checksum = FW_DEFAULT_CHECKSUM;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci		/* convert offset from words to bytes */
39962306a36Sopenharmony_ci		buffer.address = (__force u32)cpu_to_be32((offset + current_word) * 2);
40062306a36Sopenharmony_ci		buffer.length = (__force u16)cpu_to_be16(words_to_read * 2);
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci		status = wx_host_interface_command(wx, (u32 *)&buffer,
40362306a36Sopenharmony_ci						   sizeof(buffer),
40462306a36Sopenharmony_ci						   WX_HI_COMMAND_TIMEOUT,
40562306a36Sopenharmony_ci						   false);
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci		if (status != 0) {
40862306a36Sopenharmony_ci			wx_err(wx, "Host interface command failed\n");
40962306a36Sopenharmony_ci			goto out;
41062306a36Sopenharmony_ci		}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci		for (i = 0; i < words_to_read; i++) {
41362306a36Sopenharmony_ci			u32 reg = WX_MNG_MBOX + (FW_NVM_DATA_OFFSET << 2) + 2 * i;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci			value = rd32(wx, reg);
41662306a36Sopenharmony_ci			data[current_word] = (u16)(value & 0xffff);
41762306a36Sopenharmony_ci			current_word++;
41862306a36Sopenharmony_ci			i++;
41962306a36Sopenharmony_ci			if (i < words_to_read) {
42062306a36Sopenharmony_ci				value >>= 16;
42162306a36Sopenharmony_ci				data[current_word] = (u16)(value & 0xffff);
42262306a36Sopenharmony_ci				current_word++;
42362306a36Sopenharmony_ci			}
42462306a36Sopenharmony_ci		}
42562306a36Sopenharmony_ci		words -= words_to_read;
42662306a36Sopenharmony_ci	}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ciout:
42962306a36Sopenharmony_ci	wx_release_sw_sync(wx, WX_MNG_SWFW_SYNC_SW_FLASH);
43062306a36Sopenharmony_ci	return status;
43162306a36Sopenharmony_ci}
43262306a36Sopenharmony_ciEXPORT_SYMBOL(wx_read_ee_hostif_buffer);
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci/**
43562306a36Sopenharmony_ci *  wx_init_eeprom_params - Initialize EEPROM params
43662306a36Sopenharmony_ci *  @wx: pointer to hardware structure
43762306a36Sopenharmony_ci *
43862306a36Sopenharmony_ci *  Initializes the EEPROM parameters wx_eeprom_info within the
43962306a36Sopenharmony_ci *  wx_hw struct in order to set up EEPROM access.
44062306a36Sopenharmony_ci **/
44162306a36Sopenharmony_civoid wx_init_eeprom_params(struct wx *wx)
44262306a36Sopenharmony_ci{
44362306a36Sopenharmony_ci	struct wx_eeprom_info *eeprom = &wx->eeprom;
44462306a36Sopenharmony_ci	u16 eeprom_size;
44562306a36Sopenharmony_ci	u16 data = 0x80;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	if (eeprom->type == wx_eeprom_uninitialized) {
44862306a36Sopenharmony_ci		eeprom->semaphore_delay = 10;
44962306a36Sopenharmony_ci		eeprom->type = wx_eeprom_none;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci		if (!(rd32(wx, WX_SPI_STATUS) &
45262306a36Sopenharmony_ci		      WX_SPI_STATUS_FLASH_BYPASS)) {
45362306a36Sopenharmony_ci			eeprom->type = wx_flash;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci			eeprom_size = 4096;
45662306a36Sopenharmony_ci			eeprom->word_size = eeprom_size >> 1;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci			wx_dbg(wx, "Eeprom params: type = %d, size = %d\n",
45962306a36Sopenharmony_ci			       eeprom->type, eeprom->word_size);
46062306a36Sopenharmony_ci		}
46162306a36Sopenharmony_ci	}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	if (wx->mac.type == wx_mac_sp) {
46462306a36Sopenharmony_ci		if (wx_read_ee_hostif(wx, WX_SW_REGION_PTR, &data)) {
46562306a36Sopenharmony_ci			wx_err(wx, "NVM Read Error\n");
46662306a36Sopenharmony_ci			return;
46762306a36Sopenharmony_ci		}
46862306a36Sopenharmony_ci		data = data >> 1;
46962306a36Sopenharmony_ci	}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	eeprom->sw_region_offset = data;
47262306a36Sopenharmony_ci}
47362306a36Sopenharmony_ciEXPORT_SYMBOL(wx_init_eeprom_params);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci/**
47662306a36Sopenharmony_ci *  wx_get_mac_addr - Generic get MAC address
47762306a36Sopenharmony_ci *  @wx: pointer to hardware structure
47862306a36Sopenharmony_ci *  @mac_addr: Adapter MAC address
47962306a36Sopenharmony_ci *
48062306a36Sopenharmony_ci *  Reads the adapter's MAC address from first Receive Address Register (RAR0)
48162306a36Sopenharmony_ci *  A reset of the adapter must be performed prior to calling this function
48262306a36Sopenharmony_ci *  in order for the MAC address to have been loaded from the EEPROM into RAR0
48362306a36Sopenharmony_ci **/
48462306a36Sopenharmony_civoid wx_get_mac_addr(struct wx *wx, u8 *mac_addr)
48562306a36Sopenharmony_ci{
48662306a36Sopenharmony_ci	u32 rar_high;
48762306a36Sopenharmony_ci	u32 rar_low;
48862306a36Sopenharmony_ci	u16 i;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	wr32(wx, WX_PSR_MAC_SWC_IDX, 0);
49162306a36Sopenharmony_ci	rar_high = rd32(wx, WX_PSR_MAC_SWC_AD_H);
49262306a36Sopenharmony_ci	rar_low = rd32(wx, WX_PSR_MAC_SWC_AD_L);
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	for (i = 0; i < 2; i++)
49562306a36Sopenharmony_ci		mac_addr[i] = (u8)(rar_high >> (1 - i) * 8);
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	for (i = 0; i < 4; i++)
49862306a36Sopenharmony_ci		mac_addr[i + 2] = (u8)(rar_low >> (3 - i) * 8);
49962306a36Sopenharmony_ci}
50062306a36Sopenharmony_ciEXPORT_SYMBOL(wx_get_mac_addr);
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci/**
50362306a36Sopenharmony_ci *  wx_set_rar - Set Rx address register
50462306a36Sopenharmony_ci *  @wx: pointer to hardware structure
50562306a36Sopenharmony_ci *  @index: Receive address register to write
50662306a36Sopenharmony_ci *  @addr: Address to put into receive address register
50762306a36Sopenharmony_ci *  @pools: VMDq "set" or "pool" index
50862306a36Sopenharmony_ci *  @enable_addr: set flag that address is active
50962306a36Sopenharmony_ci *
51062306a36Sopenharmony_ci *  Puts an ethernet address into a receive address register.
51162306a36Sopenharmony_ci **/
51262306a36Sopenharmony_cistatic int wx_set_rar(struct wx *wx, u32 index, u8 *addr, u64 pools,
51362306a36Sopenharmony_ci		      u32 enable_addr)
51462306a36Sopenharmony_ci{
51562306a36Sopenharmony_ci	u32 rar_entries = wx->mac.num_rar_entries;
51662306a36Sopenharmony_ci	u32 rar_low, rar_high;
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	/* Make sure we are using a valid rar index range */
51962306a36Sopenharmony_ci	if (index >= rar_entries) {
52062306a36Sopenharmony_ci		wx_err(wx, "RAR index %d is out of range.\n", index);
52162306a36Sopenharmony_ci		return -EINVAL;
52262306a36Sopenharmony_ci	}
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	/* select the MAC address */
52562306a36Sopenharmony_ci	wr32(wx, WX_PSR_MAC_SWC_IDX, index);
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	/* setup VMDq pool mapping */
52862306a36Sopenharmony_ci	wr32(wx, WX_PSR_MAC_SWC_VM_L, pools & 0xFFFFFFFF);
52962306a36Sopenharmony_ci	if (wx->mac.type == wx_mac_sp)
53062306a36Sopenharmony_ci		wr32(wx, WX_PSR_MAC_SWC_VM_H, pools >> 32);
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	/* HW expects these in little endian so we reverse the byte
53362306a36Sopenharmony_ci	 * order from network order (big endian) to little endian
53462306a36Sopenharmony_ci	 *
53562306a36Sopenharmony_ci	 * Some parts put the VMDq setting in the extra RAH bits,
53662306a36Sopenharmony_ci	 * so save everything except the lower 16 bits that hold part
53762306a36Sopenharmony_ci	 * of the address and the address valid bit.
53862306a36Sopenharmony_ci	 */
53962306a36Sopenharmony_ci	rar_low = ((u32)addr[5] |
54062306a36Sopenharmony_ci		  ((u32)addr[4] << 8) |
54162306a36Sopenharmony_ci		  ((u32)addr[3] << 16) |
54262306a36Sopenharmony_ci		  ((u32)addr[2] << 24));
54362306a36Sopenharmony_ci	rar_high = ((u32)addr[1] |
54462306a36Sopenharmony_ci		   ((u32)addr[0] << 8));
54562306a36Sopenharmony_ci	if (enable_addr != 0)
54662306a36Sopenharmony_ci		rar_high |= WX_PSR_MAC_SWC_AD_H_AV;
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	wr32(wx, WX_PSR_MAC_SWC_AD_L, rar_low);
54962306a36Sopenharmony_ci	wr32m(wx, WX_PSR_MAC_SWC_AD_H,
55062306a36Sopenharmony_ci	      (WX_PSR_MAC_SWC_AD_H_AD(U16_MAX) |
55162306a36Sopenharmony_ci	       WX_PSR_MAC_SWC_AD_H_ADTYPE(1) |
55262306a36Sopenharmony_ci	       WX_PSR_MAC_SWC_AD_H_AV),
55362306a36Sopenharmony_ci	      rar_high);
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	return 0;
55662306a36Sopenharmony_ci}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci/**
55962306a36Sopenharmony_ci *  wx_clear_rar - Remove Rx address register
56062306a36Sopenharmony_ci *  @wx: pointer to hardware structure
56162306a36Sopenharmony_ci *  @index: Receive address register to write
56262306a36Sopenharmony_ci *
56362306a36Sopenharmony_ci *  Clears an ethernet address from a receive address register.
56462306a36Sopenharmony_ci **/
56562306a36Sopenharmony_cistatic int wx_clear_rar(struct wx *wx, u32 index)
56662306a36Sopenharmony_ci{
56762306a36Sopenharmony_ci	u32 rar_entries = wx->mac.num_rar_entries;
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	/* Make sure we are using a valid rar index range */
57062306a36Sopenharmony_ci	if (index >= rar_entries) {
57162306a36Sopenharmony_ci		wx_err(wx, "RAR index %d is out of range.\n", index);
57262306a36Sopenharmony_ci		return -EINVAL;
57362306a36Sopenharmony_ci	}
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	/* Some parts put the VMDq setting in the extra RAH bits,
57662306a36Sopenharmony_ci	 * so save everything except the lower 16 bits that hold part
57762306a36Sopenharmony_ci	 * of the address and the address valid bit.
57862306a36Sopenharmony_ci	 */
57962306a36Sopenharmony_ci	wr32(wx, WX_PSR_MAC_SWC_IDX, index);
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	wr32(wx, WX_PSR_MAC_SWC_VM_L, 0);
58262306a36Sopenharmony_ci	wr32(wx, WX_PSR_MAC_SWC_VM_H, 0);
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	wr32(wx, WX_PSR_MAC_SWC_AD_L, 0);
58562306a36Sopenharmony_ci	wr32m(wx, WX_PSR_MAC_SWC_AD_H,
58662306a36Sopenharmony_ci	      (WX_PSR_MAC_SWC_AD_H_AD(U16_MAX) |
58762306a36Sopenharmony_ci	       WX_PSR_MAC_SWC_AD_H_ADTYPE(1) |
58862306a36Sopenharmony_ci	       WX_PSR_MAC_SWC_AD_H_AV),
58962306a36Sopenharmony_ci	      0);
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	return 0;
59262306a36Sopenharmony_ci}
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci/**
59562306a36Sopenharmony_ci *  wx_clear_vmdq - Disassociate a VMDq pool index from a rx address
59662306a36Sopenharmony_ci *  @wx: pointer to hardware struct
59762306a36Sopenharmony_ci *  @rar: receive address register index to disassociate
59862306a36Sopenharmony_ci *  @vmdq: VMDq pool index to remove from the rar
59962306a36Sopenharmony_ci **/
60062306a36Sopenharmony_cistatic int wx_clear_vmdq(struct wx *wx, u32 rar, u32 __maybe_unused vmdq)
60162306a36Sopenharmony_ci{
60262306a36Sopenharmony_ci	u32 rar_entries = wx->mac.num_rar_entries;
60362306a36Sopenharmony_ci	u32 mpsar_lo, mpsar_hi;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	/* Make sure we are using a valid rar index range */
60662306a36Sopenharmony_ci	if (rar >= rar_entries) {
60762306a36Sopenharmony_ci		wx_err(wx, "RAR index %d is out of range.\n", rar);
60862306a36Sopenharmony_ci		return -EINVAL;
60962306a36Sopenharmony_ci	}
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	wr32(wx, WX_PSR_MAC_SWC_IDX, rar);
61262306a36Sopenharmony_ci	mpsar_lo = rd32(wx, WX_PSR_MAC_SWC_VM_L);
61362306a36Sopenharmony_ci	mpsar_hi = rd32(wx, WX_PSR_MAC_SWC_VM_H);
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	if (!mpsar_lo && !mpsar_hi)
61662306a36Sopenharmony_ci		return 0;
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	/* was that the last pool using this rar? */
61962306a36Sopenharmony_ci	if (mpsar_lo == 0 && mpsar_hi == 0 && rar != 0)
62062306a36Sopenharmony_ci		wx_clear_rar(wx, rar);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	return 0;
62362306a36Sopenharmony_ci}
62462306a36Sopenharmony_ci
62562306a36Sopenharmony_ci/**
62662306a36Sopenharmony_ci *  wx_init_uta_tables - Initialize the Unicast Table Array
62762306a36Sopenharmony_ci *  @wx: pointer to hardware structure
62862306a36Sopenharmony_ci **/
62962306a36Sopenharmony_cistatic void wx_init_uta_tables(struct wx *wx)
63062306a36Sopenharmony_ci{
63162306a36Sopenharmony_ci	int i;
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	wx_dbg(wx, " Clearing UTA\n");
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	for (i = 0; i < 128; i++)
63662306a36Sopenharmony_ci		wr32(wx, WX_PSR_UC_TBL(i), 0);
63762306a36Sopenharmony_ci}
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci/**
64062306a36Sopenharmony_ci *  wx_init_rx_addrs - Initializes receive address filters.
64162306a36Sopenharmony_ci *  @wx: pointer to hardware structure
64262306a36Sopenharmony_ci *
64362306a36Sopenharmony_ci *  Places the MAC address in receive address register 0 and clears the rest
64462306a36Sopenharmony_ci *  of the receive address registers. Clears the multicast table. Assumes
64562306a36Sopenharmony_ci *  the receiver is in reset when the routine is called.
64662306a36Sopenharmony_ci **/
64762306a36Sopenharmony_civoid wx_init_rx_addrs(struct wx *wx)
64862306a36Sopenharmony_ci{
64962306a36Sopenharmony_ci	u32 rar_entries = wx->mac.num_rar_entries;
65062306a36Sopenharmony_ci	u32 psrctl;
65162306a36Sopenharmony_ci	int i;
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	/* If the current mac address is valid, assume it is a software override
65462306a36Sopenharmony_ci	 * to the permanent address.
65562306a36Sopenharmony_ci	 * Otherwise, use the permanent address from the eeprom.
65662306a36Sopenharmony_ci	 */
65762306a36Sopenharmony_ci	if (!is_valid_ether_addr(wx->mac.addr)) {
65862306a36Sopenharmony_ci		/* Get the MAC address from the RAR0 for later reference */
65962306a36Sopenharmony_ci		wx_get_mac_addr(wx, wx->mac.addr);
66062306a36Sopenharmony_ci		wx_dbg(wx, "Keeping Current RAR0 Addr = %pM\n", wx->mac.addr);
66162306a36Sopenharmony_ci	} else {
66262306a36Sopenharmony_ci		/* Setup the receive address. */
66362306a36Sopenharmony_ci		wx_dbg(wx, "Overriding MAC Address in RAR[0]\n");
66462306a36Sopenharmony_ci		wx_dbg(wx, "New MAC Addr = %pM\n", wx->mac.addr);
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci		wx_set_rar(wx, 0, wx->mac.addr, 0, WX_PSR_MAC_SWC_AD_H_AV);
66762306a36Sopenharmony_ci
66862306a36Sopenharmony_ci		if (wx->mac.type == wx_mac_sp) {
66962306a36Sopenharmony_ci			/* clear VMDq pool/queue selection for RAR 0 */
67062306a36Sopenharmony_ci			wx_clear_vmdq(wx, 0, WX_CLEAR_VMDQ_ALL);
67162306a36Sopenharmony_ci		}
67262306a36Sopenharmony_ci	}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	/* Zero out the other receive addresses. */
67562306a36Sopenharmony_ci	wx_dbg(wx, "Clearing RAR[1-%d]\n", rar_entries - 1);
67662306a36Sopenharmony_ci	for (i = 1; i < rar_entries; i++) {
67762306a36Sopenharmony_ci		wr32(wx, WX_PSR_MAC_SWC_IDX, i);
67862306a36Sopenharmony_ci		wr32(wx, WX_PSR_MAC_SWC_AD_L, 0);
67962306a36Sopenharmony_ci		wr32(wx, WX_PSR_MAC_SWC_AD_H, 0);
68062306a36Sopenharmony_ci	}
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	/* Clear the MTA */
68362306a36Sopenharmony_ci	wx->addr_ctrl.mta_in_use = 0;
68462306a36Sopenharmony_ci	psrctl = rd32(wx, WX_PSR_CTL);
68562306a36Sopenharmony_ci	psrctl &= ~(WX_PSR_CTL_MO | WX_PSR_CTL_MFE);
68662306a36Sopenharmony_ci	psrctl |= wx->mac.mc_filter_type << WX_PSR_CTL_MO_SHIFT;
68762306a36Sopenharmony_ci	wr32(wx, WX_PSR_CTL, psrctl);
68862306a36Sopenharmony_ci	wx_dbg(wx, " Clearing MTA\n");
68962306a36Sopenharmony_ci	for (i = 0; i < wx->mac.mcft_size; i++)
69062306a36Sopenharmony_ci		wr32(wx, WX_PSR_MC_TBL(i), 0);
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	wx_init_uta_tables(wx);
69362306a36Sopenharmony_ci}
69462306a36Sopenharmony_ciEXPORT_SYMBOL(wx_init_rx_addrs);
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_cistatic void wx_sync_mac_table(struct wx *wx)
69762306a36Sopenharmony_ci{
69862306a36Sopenharmony_ci	int i;
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	for (i = 0; i < wx->mac.num_rar_entries; i++) {
70162306a36Sopenharmony_ci		if (wx->mac_table[i].state & WX_MAC_STATE_MODIFIED) {
70262306a36Sopenharmony_ci			if (wx->mac_table[i].state & WX_MAC_STATE_IN_USE) {
70362306a36Sopenharmony_ci				wx_set_rar(wx, i,
70462306a36Sopenharmony_ci					   wx->mac_table[i].addr,
70562306a36Sopenharmony_ci					   wx->mac_table[i].pools,
70662306a36Sopenharmony_ci					   WX_PSR_MAC_SWC_AD_H_AV);
70762306a36Sopenharmony_ci			} else {
70862306a36Sopenharmony_ci				wx_clear_rar(wx, i);
70962306a36Sopenharmony_ci			}
71062306a36Sopenharmony_ci			wx->mac_table[i].state &= ~(WX_MAC_STATE_MODIFIED);
71162306a36Sopenharmony_ci		}
71262306a36Sopenharmony_ci	}
71362306a36Sopenharmony_ci}
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci/* this function destroys the first RAR entry */
71662306a36Sopenharmony_civoid wx_mac_set_default_filter(struct wx *wx, u8 *addr)
71762306a36Sopenharmony_ci{
71862306a36Sopenharmony_ci	memcpy(&wx->mac_table[0].addr, addr, ETH_ALEN);
71962306a36Sopenharmony_ci	wx->mac_table[0].pools = 1ULL;
72062306a36Sopenharmony_ci	wx->mac_table[0].state = (WX_MAC_STATE_DEFAULT | WX_MAC_STATE_IN_USE);
72162306a36Sopenharmony_ci	wx_set_rar(wx, 0, wx->mac_table[0].addr,
72262306a36Sopenharmony_ci		   wx->mac_table[0].pools,
72362306a36Sopenharmony_ci		   WX_PSR_MAC_SWC_AD_H_AV);
72462306a36Sopenharmony_ci}
72562306a36Sopenharmony_ciEXPORT_SYMBOL(wx_mac_set_default_filter);
72662306a36Sopenharmony_ci
72762306a36Sopenharmony_civoid wx_flush_sw_mac_table(struct wx *wx)
72862306a36Sopenharmony_ci{
72962306a36Sopenharmony_ci	u32 i;
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	for (i = 0; i < wx->mac.num_rar_entries; i++) {
73262306a36Sopenharmony_ci		if (!(wx->mac_table[i].state & WX_MAC_STATE_IN_USE))
73362306a36Sopenharmony_ci			continue;
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci		wx->mac_table[i].state |= WX_MAC_STATE_MODIFIED;
73662306a36Sopenharmony_ci		wx->mac_table[i].state &= ~WX_MAC_STATE_IN_USE;
73762306a36Sopenharmony_ci		memset(wx->mac_table[i].addr, 0, ETH_ALEN);
73862306a36Sopenharmony_ci		wx->mac_table[i].pools = 0;
73962306a36Sopenharmony_ci	}
74062306a36Sopenharmony_ci	wx_sync_mac_table(wx);
74162306a36Sopenharmony_ci}
74262306a36Sopenharmony_ciEXPORT_SYMBOL(wx_flush_sw_mac_table);
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_cistatic int wx_add_mac_filter(struct wx *wx, u8 *addr, u16 pool)
74562306a36Sopenharmony_ci{
74662306a36Sopenharmony_ci	u32 i;
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	if (is_zero_ether_addr(addr))
74962306a36Sopenharmony_ci		return -EINVAL;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	for (i = 0; i < wx->mac.num_rar_entries; i++) {
75262306a36Sopenharmony_ci		if (wx->mac_table[i].state & WX_MAC_STATE_IN_USE) {
75362306a36Sopenharmony_ci			if (ether_addr_equal(addr, wx->mac_table[i].addr)) {
75462306a36Sopenharmony_ci				if (wx->mac_table[i].pools != (1ULL << pool)) {
75562306a36Sopenharmony_ci					memcpy(wx->mac_table[i].addr, addr, ETH_ALEN);
75662306a36Sopenharmony_ci					wx->mac_table[i].pools |= (1ULL << pool);
75762306a36Sopenharmony_ci					wx_sync_mac_table(wx);
75862306a36Sopenharmony_ci					return i;
75962306a36Sopenharmony_ci				}
76062306a36Sopenharmony_ci			}
76162306a36Sopenharmony_ci		}
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci		if (wx->mac_table[i].state & WX_MAC_STATE_IN_USE)
76462306a36Sopenharmony_ci			continue;
76562306a36Sopenharmony_ci		wx->mac_table[i].state |= (WX_MAC_STATE_MODIFIED |
76662306a36Sopenharmony_ci					   WX_MAC_STATE_IN_USE);
76762306a36Sopenharmony_ci		memcpy(wx->mac_table[i].addr, addr, ETH_ALEN);
76862306a36Sopenharmony_ci		wx->mac_table[i].pools |= (1ULL << pool);
76962306a36Sopenharmony_ci		wx_sync_mac_table(wx);
77062306a36Sopenharmony_ci		return i;
77162306a36Sopenharmony_ci	}
77262306a36Sopenharmony_ci	return -ENOMEM;
77362306a36Sopenharmony_ci}
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_cistatic int wx_del_mac_filter(struct wx *wx, u8 *addr, u16 pool)
77662306a36Sopenharmony_ci{
77762306a36Sopenharmony_ci	u32 i;
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	if (is_zero_ether_addr(addr))
78062306a36Sopenharmony_ci		return -EINVAL;
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	/* search table for addr, if found, set to 0 and sync */
78362306a36Sopenharmony_ci	for (i = 0; i < wx->mac.num_rar_entries; i++) {
78462306a36Sopenharmony_ci		if (!ether_addr_equal(addr, wx->mac_table[i].addr))
78562306a36Sopenharmony_ci			continue;
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_ci		wx->mac_table[i].state |= WX_MAC_STATE_MODIFIED;
78862306a36Sopenharmony_ci		wx->mac_table[i].pools &= ~(1ULL << pool);
78962306a36Sopenharmony_ci		if (!wx->mac_table[i].pools) {
79062306a36Sopenharmony_ci			wx->mac_table[i].state &= ~WX_MAC_STATE_IN_USE;
79162306a36Sopenharmony_ci			memset(wx->mac_table[i].addr, 0, ETH_ALEN);
79262306a36Sopenharmony_ci		}
79362306a36Sopenharmony_ci		wx_sync_mac_table(wx);
79462306a36Sopenharmony_ci		return 0;
79562306a36Sopenharmony_ci	}
79662306a36Sopenharmony_ci	return -ENOMEM;
79762306a36Sopenharmony_ci}
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_cistatic int wx_available_rars(struct wx *wx)
80062306a36Sopenharmony_ci{
80162306a36Sopenharmony_ci	u32 i, count = 0;
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	for (i = 0; i < wx->mac.num_rar_entries; i++) {
80462306a36Sopenharmony_ci		if (wx->mac_table[i].state == 0)
80562306a36Sopenharmony_ci			count++;
80662306a36Sopenharmony_ci	}
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	return count;
80962306a36Sopenharmony_ci}
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci/**
81262306a36Sopenharmony_ci * wx_write_uc_addr_list - write unicast addresses to RAR table
81362306a36Sopenharmony_ci * @netdev: network interface device structure
81462306a36Sopenharmony_ci * @pool: index for mac table
81562306a36Sopenharmony_ci *
81662306a36Sopenharmony_ci * Writes unicast address list to the RAR table.
81762306a36Sopenharmony_ci * Returns: -ENOMEM on failure/insufficient address space
81862306a36Sopenharmony_ci *                0 on no addresses written
81962306a36Sopenharmony_ci *                X on writing X addresses to the RAR table
82062306a36Sopenharmony_ci **/
82162306a36Sopenharmony_cistatic int wx_write_uc_addr_list(struct net_device *netdev, int pool)
82262306a36Sopenharmony_ci{
82362306a36Sopenharmony_ci	struct wx *wx = netdev_priv(netdev);
82462306a36Sopenharmony_ci	int count = 0;
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	/* return ENOMEM indicating insufficient memory for addresses */
82762306a36Sopenharmony_ci	if (netdev_uc_count(netdev) > wx_available_rars(wx))
82862306a36Sopenharmony_ci		return -ENOMEM;
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	if (!netdev_uc_empty(netdev)) {
83162306a36Sopenharmony_ci		struct netdev_hw_addr *ha;
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci		netdev_for_each_uc_addr(ha, netdev) {
83462306a36Sopenharmony_ci			wx_del_mac_filter(wx, ha->addr, pool);
83562306a36Sopenharmony_ci			wx_add_mac_filter(wx, ha->addr, pool);
83662306a36Sopenharmony_ci			count++;
83762306a36Sopenharmony_ci		}
83862306a36Sopenharmony_ci	}
83962306a36Sopenharmony_ci	return count;
84062306a36Sopenharmony_ci}
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci/**
84362306a36Sopenharmony_ci *  wx_mta_vector - Determines bit-vector in multicast table to set
84462306a36Sopenharmony_ci *  @wx: pointer to private structure
84562306a36Sopenharmony_ci *  @mc_addr: the multicast address
84662306a36Sopenharmony_ci *
84762306a36Sopenharmony_ci *  Extracts the 12 bits, from a multicast address, to determine which
84862306a36Sopenharmony_ci *  bit-vector to set in the multicast table. The hardware uses 12 bits, from
84962306a36Sopenharmony_ci *  incoming rx multicast addresses, to determine the bit-vector to check in
85062306a36Sopenharmony_ci *  the MTA. Which of the 4 combination, of 12-bits, the hardware uses is set
85162306a36Sopenharmony_ci *  by the MO field of the MCSTCTRL. The MO field is set during initialization
85262306a36Sopenharmony_ci *  to mc_filter_type.
85362306a36Sopenharmony_ci **/
85462306a36Sopenharmony_cistatic u32 wx_mta_vector(struct wx *wx, u8 *mc_addr)
85562306a36Sopenharmony_ci{
85662306a36Sopenharmony_ci	u32 vector = 0;
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	switch (wx->mac.mc_filter_type) {
85962306a36Sopenharmony_ci	case 0:   /* use bits [47:36] of the address */
86062306a36Sopenharmony_ci		vector = ((mc_addr[4] >> 4) | (((u16)mc_addr[5]) << 4));
86162306a36Sopenharmony_ci		break;
86262306a36Sopenharmony_ci	case 1:   /* use bits [46:35] of the address */
86362306a36Sopenharmony_ci		vector = ((mc_addr[4] >> 3) | (((u16)mc_addr[5]) << 5));
86462306a36Sopenharmony_ci		break;
86562306a36Sopenharmony_ci	case 2:   /* use bits [45:34] of the address */
86662306a36Sopenharmony_ci		vector = ((mc_addr[4] >> 2) | (((u16)mc_addr[5]) << 6));
86762306a36Sopenharmony_ci		break;
86862306a36Sopenharmony_ci	case 3:   /* use bits [43:32] of the address */
86962306a36Sopenharmony_ci		vector = ((mc_addr[4]) | (((u16)mc_addr[5]) << 8));
87062306a36Sopenharmony_ci		break;
87162306a36Sopenharmony_ci	default:  /* Invalid mc_filter_type */
87262306a36Sopenharmony_ci		wx_err(wx, "MC filter type param set incorrectly\n");
87362306a36Sopenharmony_ci		break;
87462306a36Sopenharmony_ci	}
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	/* vector can only be 12-bits or boundary will be exceeded */
87762306a36Sopenharmony_ci	vector &= 0xFFF;
87862306a36Sopenharmony_ci	return vector;
87962306a36Sopenharmony_ci}
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci/**
88262306a36Sopenharmony_ci *  wx_set_mta - Set bit-vector in multicast table
88362306a36Sopenharmony_ci *  @wx: pointer to private structure
88462306a36Sopenharmony_ci *  @mc_addr: Multicast address
88562306a36Sopenharmony_ci *
88662306a36Sopenharmony_ci *  Sets the bit-vector in the multicast table.
88762306a36Sopenharmony_ci **/
88862306a36Sopenharmony_cistatic void wx_set_mta(struct wx *wx, u8 *mc_addr)
88962306a36Sopenharmony_ci{
89062306a36Sopenharmony_ci	u32 vector, vector_bit, vector_reg;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	wx->addr_ctrl.mta_in_use++;
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	vector = wx_mta_vector(wx, mc_addr);
89562306a36Sopenharmony_ci	wx_dbg(wx, " bit-vector = 0x%03X\n", vector);
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	/* The MTA is a register array of 128 32-bit registers. It is treated
89862306a36Sopenharmony_ci	 * like an array of 4096 bits.  We want to set bit
89962306a36Sopenharmony_ci	 * BitArray[vector_value]. So we figure out what register the bit is
90062306a36Sopenharmony_ci	 * in, read it, OR in the new bit, then write back the new value.  The
90162306a36Sopenharmony_ci	 * register is determined by the upper 7 bits of the vector value and
90262306a36Sopenharmony_ci	 * the bit within that register are determined by the lower 5 bits of
90362306a36Sopenharmony_ci	 * the value.
90462306a36Sopenharmony_ci	 */
90562306a36Sopenharmony_ci	vector_reg = (vector >> 5) & 0x7F;
90662306a36Sopenharmony_ci	vector_bit = vector & 0x1F;
90762306a36Sopenharmony_ci	wx->mac.mta_shadow[vector_reg] |= (1 << vector_bit);
90862306a36Sopenharmony_ci}
90962306a36Sopenharmony_ci
91062306a36Sopenharmony_ci/**
91162306a36Sopenharmony_ci *  wx_update_mc_addr_list - Updates MAC list of multicast addresses
91262306a36Sopenharmony_ci *  @wx: pointer to private structure
91362306a36Sopenharmony_ci *  @netdev: pointer to net device structure
91462306a36Sopenharmony_ci *
91562306a36Sopenharmony_ci *  The given list replaces any existing list. Clears the MC addrs from receive
91662306a36Sopenharmony_ci *  address registers and the multicast table. Uses unused receive address
91762306a36Sopenharmony_ci *  registers for the first multicast addresses, and hashes the rest into the
91862306a36Sopenharmony_ci *  multicast table.
91962306a36Sopenharmony_ci **/
92062306a36Sopenharmony_cistatic void wx_update_mc_addr_list(struct wx *wx, struct net_device *netdev)
92162306a36Sopenharmony_ci{
92262306a36Sopenharmony_ci	struct netdev_hw_addr *ha;
92362306a36Sopenharmony_ci	u32 i, psrctl;
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci	/* Set the new number of MC addresses that we are being requested to
92662306a36Sopenharmony_ci	 * use.
92762306a36Sopenharmony_ci	 */
92862306a36Sopenharmony_ci	wx->addr_ctrl.num_mc_addrs = netdev_mc_count(netdev);
92962306a36Sopenharmony_ci	wx->addr_ctrl.mta_in_use = 0;
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	/* Clear mta_shadow */
93262306a36Sopenharmony_ci	wx_dbg(wx, " Clearing MTA\n");
93362306a36Sopenharmony_ci	memset(&wx->mac.mta_shadow, 0, sizeof(wx->mac.mta_shadow));
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	/* Update mta_shadow */
93662306a36Sopenharmony_ci	netdev_for_each_mc_addr(ha, netdev) {
93762306a36Sopenharmony_ci		wx_dbg(wx, " Adding the multicast addresses:\n");
93862306a36Sopenharmony_ci		wx_set_mta(wx, ha->addr);
93962306a36Sopenharmony_ci	}
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_ci	/* Enable mta */
94262306a36Sopenharmony_ci	for (i = 0; i < wx->mac.mcft_size; i++)
94362306a36Sopenharmony_ci		wr32a(wx, WX_PSR_MC_TBL(0), i,
94462306a36Sopenharmony_ci		      wx->mac.mta_shadow[i]);
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	if (wx->addr_ctrl.mta_in_use > 0) {
94762306a36Sopenharmony_ci		psrctl = rd32(wx, WX_PSR_CTL);
94862306a36Sopenharmony_ci		psrctl &= ~(WX_PSR_CTL_MO | WX_PSR_CTL_MFE);
94962306a36Sopenharmony_ci		psrctl |= WX_PSR_CTL_MFE |
95062306a36Sopenharmony_ci			  (wx->mac.mc_filter_type << WX_PSR_CTL_MO_SHIFT);
95162306a36Sopenharmony_ci		wr32(wx, WX_PSR_CTL, psrctl);
95262306a36Sopenharmony_ci	}
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	wx_dbg(wx, "Update mc addr list Complete\n");
95562306a36Sopenharmony_ci}
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci/**
95862306a36Sopenharmony_ci * wx_write_mc_addr_list - write multicast addresses to MTA
95962306a36Sopenharmony_ci * @netdev: network interface device structure
96062306a36Sopenharmony_ci *
96162306a36Sopenharmony_ci * Writes multicast address list to the MTA hash table.
96262306a36Sopenharmony_ci * Returns: 0 on no addresses written
96362306a36Sopenharmony_ci *          X on writing X addresses to MTA
96462306a36Sopenharmony_ci **/
96562306a36Sopenharmony_cistatic int wx_write_mc_addr_list(struct net_device *netdev)
96662306a36Sopenharmony_ci{
96762306a36Sopenharmony_ci	struct wx *wx = netdev_priv(netdev);
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	if (!netif_running(netdev))
97062306a36Sopenharmony_ci		return 0;
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	wx_update_mc_addr_list(wx, netdev);
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	return netdev_mc_count(netdev);
97562306a36Sopenharmony_ci}
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci/**
97862306a36Sopenharmony_ci * wx_set_mac - Change the Ethernet Address of the NIC
97962306a36Sopenharmony_ci * @netdev: network interface device structure
98062306a36Sopenharmony_ci * @p: pointer to an address structure
98162306a36Sopenharmony_ci *
98262306a36Sopenharmony_ci * Returns 0 on success, negative on failure
98362306a36Sopenharmony_ci **/
98462306a36Sopenharmony_ciint wx_set_mac(struct net_device *netdev, void *p)
98562306a36Sopenharmony_ci{
98662306a36Sopenharmony_ci	struct wx *wx = netdev_priv(netdev);
98762306a36Sopenharmony_ci	struct sockaddr *addr = p;
98862306a36Sopenharmony_ci	int retval;
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci	retval = eth_prepare_mac_addr_change(netdev, addr);
99162306a36Sopenharmony_ci	if (retval)
99262306a36Sopenharmony_ci		return retval;
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	wx_del_mac_filter(wx, wx->mac.addr, 0);
99562306a36Sopenharmony_ci	eth_hw_addr_set(netdev, addr->sa_data);
99662306a36Sopenharmony_ci	memcpy(wx->mac.addr, addr->sa_data, netdev->addr_len);
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	wx_mac_set_default_filter(wx, wx->mac.addr);
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	return 0;
100162306a36Sopenharmony_ci}
100262306a36Sopenharmony_ciEXPORT_SYMBOL(wx_set_mac);
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_civoid wx_disable_rx(struct wx *wx)
100562306a36Sopenharmony_ci{
100662306a36Sopenharmony_ci	u32 pfdtxgswc;
100762306a36Sopenharmony_ci	u32 rxctrl;
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	rxctrl = rd32(wx, WX_RDB_PB_CTL);
101062306a36Sopenharmony_ci	if (rxctrl & WX_RDB_PB_CTL_RXEN) {
101162306a36Sopenharmony_ci		pfdtxgswc = rd32(wx, WX_PSR_CTL);
101262306a36Sopenharmony_ci		if (pfdtxgswc & WX_PSR_CTL_SW_EN) {
101362306a36Sopenharmony_ci			pfdtxgswc &= ~WX_PSR_CTL_SW_EN;
101462306a36Sopenharmony_ci			wr32(wx, WX_PSR_CTL, pfdtxgswc);
101562306a36Sopenharmony_ci			wx->mac.set_lben = true;
101662306a36Sopenharmony_ci		} else {
101762306a36Sopenharmony_ci			wx->mac.set_lben = false;
101862306a36Sopenharmony_ci		}
101962306a36Sopenharmony_ci		rxctrl &= ~WX_RDB_PB_CTL_RXEN;
102062306a36Sopenharmony_ci		wr32(wx, WX_RDB_PB_CTL, rxctrl);
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci		if (!(((wx->subsystem_device_id & WX_NCSI_MASK) == WX_NCSI_SUP) ||
102362306a36Sopenharmony_ci		      ((wx->subsystem_device_id & WX_WOL_MASK) == WX_WOL_SUP))) {
102462306a36Sopenharmony_ci			/* disable mac receiver */
102562306a36Sopenharmony_ci			wr32m(wx, WX_MAC_RX_CFG,
102662306a36Sopenharmony_ci			      WX_MAC_RX_CFG_RE, 0);
102762306a36Sopenharmony_ci		}
102862306a36Sopenharmony_ci	}
102962306a36Sopenharmony_ci}
103062306a36Sopenharmony_ciEXPORT_SYMBOL(wx_disable_rx);
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_cistatic void wx_enable_rx(struct wx *wx)
103362306a36Sopenharmony_ci{
103462306a36Sopenharmony_ci	u32 psrctl;
103562306a36Sopenharmony_ci
103662306a36Sopenharmony_ci	/* enable mac receiver */
103762306a36Sopenharmony_ci	wr32m(wx, WX_MAC_RX_CFG,
103862306a36Sopenharmony_ci	      WX_MAC_RX_CFG_RE, WX_MAC_RX_CFG_RE);
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci	wr32m(wx, WX_RDB_PB_CTL,
104162306a36Sopenharmony_ci	      WX_RDB_PB_CTL_RXEN, WX_RDB_PB_CTL_RXEN);
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	if (wx->mac.set_lben) {
104462306a36Sopenharmony_ci		psrctl = rd32(wx, WX_PSR_CTL);
104562306a36Sopenharmony_ci		psrctl |= WX_PSR_CTL_SW_EN;
104662306a36Sopenharmony_ci		wr32(wx, WX_PSR_CTL, psrctl);
104762306a36Sopenharmony_ci		wx->mac.set_lben = false;
104862306a36Sopenharmony_ci	}
104962306a36Sopenharmony_ci}
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci/**
105262306a36Sopenharmony_ci * wx_set_rxpba - Initialize Rx packet buffer
105362306a36Sopenharmony_ci * @wx: pointer to private structure
105462306a36Sopenharmony_ci **/
105562306a36Sopenharmony_cistatic void wx_set_rxpba(struct wx *wx)
105662306a36Sopenharmony_ci{
105762306a36Sopenharmony_ci	u32 rxpktsize, txpktsize, txpbthresh;
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	rxpktsize = wx->mac.rx_pb_size << WX_RDB_PB_SZ_SHIFT;
106062306a36Sopenharmony_ci	wr32(wx, WX_RDB_PB_SZ(0), rxpktsize);
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	/* Only support an equally distributed Tx packet buffer strategy. */
106362306a36Sopenharmony_ci	txpktsize = wx->mac.tx_pb_size;
106462306a36Sopenharmony_ci	txpbthresh = (txpktsize / 1024) - WX_TXPKT_SIZE_MAX;
106562306a36Sopenharmony_ci	wr32(wx, WX_TDB_PB_SZ(0), txpktsize);
106662306a36Sopenharmony_ci	wr32(wx, WX_TDM_PB_THRE(0), txpbthresh);
106762306a36Sopenharmony_ci}
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_cistatic void wx_configure_port(struct wx *wx)
107062306a36Sopenharmony_ci{
107162306a36Sopenharmony_ci	u32 value, i;
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	value = WX_CFG_PORT_CTL_D_VLAN | WX_CFG_PORT_CTL_QINQ;
107462306a36Sopenharmony_ci	wr32m(wx, WX_CFG_PORT_CTL,
107562306a36Sopenharmony_ci	      WX_CFG_PORT_CTL_D_VLAN |
107662306a36Sopenharmony_ci	      WX_CFG_PORT_CTL_QINQ,
107762306a36Sopenharmony_ci	      value);
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	wr32(wx, WX_CFG_TAG_TPID(0),
108062306a36Sopenharmony_ci	     ETH_P_8021Q | ETH_P_8021AD << 16);
108162306a36Sopenharmony_ci	wx->tpid[0] = ETH_P_8021Q;
108262306a36Sopenharmony_ci	wx->tpid[1] = ETH_P_8021AD;
108362306a36Sopenharmony_ci	for (i = 1; i < 4; i++)
108462306a36Sopenharmony_ci		wr32(wx, WX_CFG_TAG_TPID(i),
108562306a36Sopenharmony_ci		     ETH_P_8021Q | ETH_P_8021Q << 16);
108662306a36Sopenharmony_ci	for (i = 2; i < 8; i++)
108762306a36Sopenharmony_ci		wx->tpid[i] = ETH_P_8021Q;
108862306a36Sopenharmony_ci}
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci/**
109162306a36Sopenharmony_ci *  wx_disable_sec_rx_path - Stops the receive data path
109262306a36Sopenharmony_ci *  @wx: pointer to private structure
109362306a36Sopenharmony_ci *
109462306a36Sopenharmony_ci *  Stops the receive data path and waits for the HW to internally empty
109562306a36Sopenharmony_ci *  the Rx security block
109662306a36Sopenharmony_ci **/
109762306a36Sopenharmony_cistatic int wx_disable_sec_rx_path(struct wx *wx)
109862306a36Sopenharmony_ci{
109962306a36Sopenharmony_ci	u32 secrx;
110062306a36Sopenharmony_ci
110162306a36Sopenharmony_ci	wr32m(wx, WX_RSC_CTL,
110262306a36Sopenharmony_ci	      WX_RSC_CTL_RX_DIS, WX_RSC_CTL_RX_DIS);
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci	return read_poll_timeout(rd32, secrx, secrx & WX_RSC_ST_RSEC_RDY,
110562306a36Sopenharmony_ci				 1000, 40000, false, wx, WX_RSC_ST);
110662306a36Sopenharmony_ci}
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci/**
110962306a36Sopenharmony_ci *  wx_enable_sec_rx_path - Enables the receive data path
111062306a36Sopenharmony_ci *  @wx: pointer to private structure
111162306a36Sopenharmony_ci *
111262306a36Sopenharmony_ci *  Enables the receive data path.
111362306a36Sopenharmony_ci **/
111462306a36Sopenharmony_cistatic void wx_enable_sec_rx_path(struct wx *wx)
111562306a36Sopenharmony_ci{
111662306a36Sopenharmony_ci	wr32m(wx, WX_RSC_CTL, WX_RSC_CTL_RX_DIS, 0);
111762306a36Sopenharmony_ci	WX_WRITE_FLUSH(wx);
111862306a36Sopenharmony_ci}
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_cistatic void wx_vlan_strip_control(struct wx *wx, bool enable)
112162306a36Sopenharmony_ci{
112262306a36Sopenharmony_ci	int i, j;
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	for (i = 0; i < wx->num_rx_queues; i++) {
112562306a36Sopenharmony_ci		struct wx_ring *ring = wx->rx_ring[i];
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci		j = ring->reg_idx;
112862306a36Sopenharmony_ci		wr32m(wx, WX_PX_RR_CFG(j), WX_PX_RR_CFG_VLAN,
112962306a36Sopenharmony_ci		      enable ? WX_PX_RR_CFG_VLAN : 0);
113062306a36Sopenharmony_ci	}
113162306a36Sopenharmony_ci}
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_civoid wx_set_rx_mode(struct net_device *netdev)
113462306a36Sopenharmony_ci{
113562306a36Sopenharmony_ci	struct wx *wx = netdev_priv(netdev);
113662306a36Sopenharmony_ci	netdev_features_t features;
113762306a36Sopenharmony_ci	u32 fctrl, vmolr, vlnctrl;
113862306a36Sopenharmony_ci	int count;
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	features = netdev->features;
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci	/* Check for Promiscuous and All Multicast modes */
114362306a36Sopenharmony_ci	fctrl = rd32(wx, WX_PSR_CTL);
114462306a36Sopenharmony_ci	fctrl &= ~(WX_PSR_CTL_UPE | WX_PSR_CTL_MPE);
114562306a36Sopenharmony_ci	vmolr = rd32(wx, WX_PSR_VM_L2CTL(0));
114662306a36Sopenharmony_ci	vmolr &= ~(WX_PSR_VM_L2CTL_UPE |
114762306a36Sopenharmony_ci		   WX_PSR_VM_L2CTL_MPE |
114862306a36Sopenharmony_ci		   WX_PSR_VM_L2CTL_ROPE |
114962306a36Sopenharmony_ci		   WX_PSR_VM_L2CTL_ROMPE);
115062306a36Sopenharmony_ci	vlnctrl = rd32(wx, WX_PSR_VLAN_CTL);
115162306a36Sopenharmony_ci	vlnctrl &= ~(WX_PSR_VLAN_CTL_VFE | WX_PSR_VLAN_CTL_CFIEN);
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	/* set all bits that we expect to always be set */
115462306a36Sopenharmony_ci	fctrl |= WX_PSR_CTL_BAM | WX_PSR_CTL_MFE;
115562306a36Sopenharmony_ci	vmolr |= WX_PSR_VM_L2CTL_BAM |
115662306a36Sopenharmony_ci		 WX_PSR_VM_L2CTL_AUPE |
115762306a36Sopenharmony_ci		 WX_PSR_VM_L2CTL_VACC;
115862306a36Sopenharmony_ci	vlnctrl |= WX_PSR_VLAN_CTL_VFE;
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_ci	wx->addr_ctrl.user_set_promisc = false;
116162306a36Sopenharmony_ci	if (netdev->flags & IFF_PROMISC) {
116262306a36Sopenharmony_ci		wx->addr_ctrl.user_set_promisc = true;
116362306a36Sopenharmony_ci		fctrl |= WX_PSR_CTL_UPE | WX_PSR_CTL_MPE;
116462306a36Sopenharmony_ci		/* pf don't want packets routing to vf, so clear UPE */
116562306a36Sopenharmony_ci		vmolr |= WX_PSR_VM_L2CTL_MPE;
116662306a36Sopenharmony_ci		vlnctrl &= ~WX_PSR_VLAN_CTL_VFE;
116762306a36Sopenharmony_ci	}
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci	if (netdev->flags & IFF_ALLMULTI) {
117062306a36Sopenharmony_ci		fctrl |= WX_PSR_CTL_MPE;
117162306a36Sopenharmony_ci		vmolr |= WX_PSR_VM_L2CTL_MPE;
117262306a36Sopenharmony_ci	}
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	if (netdev->features & NETIF_F_RXALL) {
117562306a36Sopenharmony_ci		vmolr |= (WX_PSR_VM_L2CTL_UPE | WX_PSR_VM_L2CTL_MPE);
117662306a36Sopenharmony_ci		vlnctrl &= ~WX_PSR_VLAN_CTL_VFE;
117762306a36Sopenharmony_ci		/* receive bad packets */
117862306a36Sopenharmony_ci		wr32m(wx, WX_RSC_CTL,
117962306a36Sopenharmony_ci		      WX_RSC_CTL_SAVE_MAC_ERR,
118062306a36Sopenharmony_ci		      WX_RSC_CTL_SAVE_MAC_ERR);
118162306a36Sopenharmony_ci	} else {
118262306a36Sopenharmony_ci		vmolr |= WX_PSR_VM_L2CTL_ROPE | WX_PSR_VM_L2CTL_ROMPE;
118362306a36Sopenharmony_ci	}
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	/* Write addresses to available RAR registers, if there is not
118662306a36Sopenharmony_ci	 * sufficient space to store all the addresses then enable
118762306a36Sopenharmony_ci	 * unicast promiscuous mode
118862306a36Sopenharmony_ci	 */
118962306a36Sopenharmony_ci	count = wx_write_uc_addr_list(netdev, 0);
119062306a36Sopenharmony_ci	if (count < 0) {
119162306a36Sopenharmony_ci		vmolr &= ~WX_PSR_VM_L2CTL_ROPE;
119262306a36Sopenharmony_ci		vmolr |= WX_PSR_VM_L2CTL_UPE;
119362306a36Sopenharmony_ci	}
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ci	/* Write addresses to the MTA, if the attempt fails
119662306a36Sopenharmony_ci	 * then we should just turn on promiscuous mode so
119762306a36Sopenharmony_ci	 * that we can at least receive multicast traffic
119862306a36Sopenharmony_ci	 */
119962306a36Sopenharmony_ci	count = wx_write_mc_addr_list(netdev);
120062306a36Sopenharmony_ci	if (count < 0) {
120162306a36Sopenharmony_ci		vmolr &= ~WX_PSR_VM_L2CTL_ROMPE;
120262306a36Sopenharmony_ci		vmolr |= WX_PSR_VM_L2CTL_MPE;
120362306a36Sopenharmony_ci	}
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	wr32(wx, WX_PSR_VLAN_CTL, vlnctrl);
120662306a36Sopenharmony_ci	wr32(wx, WX_PSR_CTL, fctrl);
120762306a36Sopenharmony_ci	wr32(wx, WX_PSR_VM_L2CTL(0), vmolr);
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	if ((features & NETIF_F_HW_VLAN_CTAG_RX) &&
121062306a36Sopenharmony_ci	    (features & NETIF_F_HW_VLAN_STAG_RX))
121162306a36Sopenharmony_ci		wx_vlan_strip_control(wx, true);
121262306a36Sopenharmony_ci	else
121362306a36Sopenharmony_ci		wx_vlan_strip_control(wx, false);
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci}
121662306a36Sopenharmony_ciEXPORT_SYMBOL(wx_set_rx_mode);
121762306a36Sopenharmony_ci
121862306a36Sopenharmony_cistatic void wx_set_rx_buffer_len(struct wx *wx)
121962306a36Sopenharmony_ci{
122062306a36Sopenharmony_ci	struct net_device *netdev = wx->netdev;
122162306a36Sopenharmony_ci	u32 mhadd, max_frame;
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
122462306a36Sopenharmony_ci	/* adjust max frame to be at least the size of a standard frame */
122562306a36Sopenharmony_ci	if (max_frame < (ETH_FRAME_LEN + ETH_FCS_LEN))
122662306a36Sopenharmony_ci		max_frame = (ETH_FRAME_LEN + ETH_FCS_LEN);
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	mhadd = rd32(wx, WX_PSR_MAX_SZ);
122962306a36Sopenharmony_ci	if (max_frame != mhadd)
123062306a36Sopenharmony_ci		wr32(wx, WX_PSR_MAX_SZ, max_frame);
123162306a36Sopenharmony_ci}
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci/**
123462306a36Sopenharmony_ci * wx_change_mtu - Change the Maximum Transfer Unit
123562306a36Sopenharmony_ci * @netdev: network interface device structure
123662306a36Sopenharmony_ci * @new_mtu: new value for maximum frame size
123762306a36Sopenharmony_ci *
123862306a36Sopenharmony_ci * Returns 0 on success, negative on failure
123962306a36Sopenharmony_ci **/
124062306a36Sopenharmony_ciint wx_change_mtu(struct net_device *netdev, int new_mtu)
124162306a36Sopenharmony_ci{
124262306a36Sopenharmony_ci	struct wx *wx = netdev_priv(netdev);
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	netdev->mtu = new_mtu;
124562306a36Sopenharmony_ci	wx_set_rx_buffer_len(wx);
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	return 0;
124862306a36Sopenharmony_ci}
124962306a36Sopenharmony_ciEXPORT_SYMBOL(wx_change_mtu);
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_ci/* Disable the specified rx queue */
125262306a36Sopenharmony_civoid wx_disable_rx_queue(struct wx *wx, struct wx_ring *ring)
125362306a36Sopenharmony_ci{
125462306a36Sopenharmony_ci	u8 reg_idx = ring->reg_idx;
125562306a36Sopenharmony_ci	u32 rxdctl;
125662306a36Sopenharmony_ci	int ret;
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci	/* write value back with RRCFG.EN bit cleared */
125962306a36Sopenharmony_ci	wr32m(wx, WX_PX_RR_CFG(reg_idx),
126062306a36Sopenharmony_ci	      WX_PX_RR_CFG_RR_EN, 0);
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	/* the hardware may take up to 100us to really disable the rx queue */
126362306a36Sopenharmony_ci	ret = read_poll_timeout(rd32, rxdctl, !(rxdctl & WX_PX_RR_CFG_RR_EN),
126462306a36Sopenharmony_ci				10, 100, true, wx, WX_PX_RR_CFG(reg_idx));
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	if (ret == -ETIMEDOUT) {
126762306a36Sopenharmony_ci		/* Just for information */
126862306a36Sopenharmony_ci		wx_err(wx,
126962306a36Sopenharmony_ci		       "RRCFG.EN on Rx queue %d not cleared within the polling period\n",
127062306a36Sopenharmony_ci		       reg_idx);
127162306a36Sopenharmony_ci	}
127262306a36Sopenharmony_ci}
127362306a36Sopenharmony_ciEXPORT_SYMBOL(wx_disable_rx_queue);
127462306a36Sopenharmony_ci
127562306a36Sopenharmony_cistatic void wx_enable_rx_queue(struct wx *wx, struct wx_ring *ring)
127662306a36Sopenharmony_ci{
127762306a36Sopenharmony_ci	u8 reg_idx = ring->reg_idx;
127862306a36Sopenharmony_ci	u32 rxdctl;
127962306a36Sopenharmony_ci	int ret;
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci	ret = read_poll_timeout(rd32, rxdctl, rxdctl & WX_PX_RR_CFG_RR_EN,
128262306a36Sopenharmony_ci				1000, 10000, true, wx, WX_PX_RR_CFG(reg_idx));
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci	if (ret == -ETIMEDOUT) {
128562306a36Sopenharmony_ci		/* Just for information */
128662306a36Sopenharmony_ci		wx_err(wx,
128762306a36Sopenharmony_ci		       "RRCFG.EN on Rx queue %d not set within the polling period\n",
128862306a36Sopenharmony_ci		       reg_idx);
128962306a36Sopenharmony_ci	}
129062306a36Sopenharmony_ci}
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_cistatic void wx_configure_srrctl(struct wx *wx,
129362306a36Sopenharmony_ci				struct wx_ring *rx_ring)
129462306a36Sopenharmony_ci{
129562306a36Sopenharmony_ci	u16 reg_idx = rx_ring->reg_idx;
129662306a36Sopenharmony_ci	u32 srrctl;
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci	srrctl = rd32(wx, WX_PX_RR_CFG(reg_idx));
129962306a36Sopenharmony_ci	srrctl &= ~(WX_PX_RR_CFG_RR_HDR_SZ |
130062306a36Sopenharmony_ci		    WX_PX_RR_CFG_RR_BUF_SZ |
130162306a36Sopenharmony_ci		    WX_PX_RR_CFG_SPLIT_MODE);
130262306a36Sopenharmony_ci	/* configure header buffer length, needed for RSC */
130362306a36Sopenharmony_ci	srrctl |= WX_RXBUFFER_256 << WX_PX_RR_CFG_BHDRSIZE_SHIFT;
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci	/* configure the packet buffer length */
130662306a36Sopenharmony_ci	srrctl |= WX_RX_BUFSZ >> WX_PX_RR_CFG_BSIZEPKT_SHIFT;
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	wr32(wx, WX_PX_RR_CFG(reg_idx), srrctl);
130962306a36Sopenharmony_ci}
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_cistatic void wx_configure_tx_ring(struct wx *wx,
131262306a36Sopenharmony_ci				 struct wx_ring *ring)
131362306a36Sopenharmony_ci{
131462306a36Sopenharmony_ci	u32 txdctl = WX_PX_TR_CFG_ENABLE;
131562306a36Sopenharmony_ci	u8 reg_idx = ring->reg_idx;
131662306a36Sopenharmony_ci	u64 tdba = ring->dma;
131762306a36Sopenharmony_ci	int ret;
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_ci	/* disable queue to avoid issues while updating state */
132062306a36Sopenharmony_ci	wr32(wx, WX_PX_TR_CFG(reg_idx), WX_PX_TR_CFG_SWFLSH);
132162306a36Sopenharmony_ci	WX_WRITE_FLUSH(wx);
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	wr32(wx, WX_PX_TR_BAL(reg_idx), tdba & DMA_BIT_MASK(32));
132462306a36Sopenharmony_ci	wr32(wx, WX_PX_TR_BAH(reg_idx), upper_32_bits(tdba));
132562306a36Sopenharmony_ci
132662306a36Sopenharmony_ci	/* reset head and tail pointers */
132762306a36Sopenharmony_ci	wr32(wx, WX_PX_TR_RP(reg_idx), 0);
132862306a36Sopenharmony_ci	wr32(wx, WX_PX_TR_WP(reg_idx), 0);
132962306a36Sopenharmony_ci	ring->tail = wx->hw_addr + WX_PX_TR_WP(reg_idx);
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	if (ring->count < WX_MAX_TXD)
133262306a36Sopenharmony_ci		txdctl |= ring->count / 128 << WX_PX_TR_CFG_TR_SIZE_SHIFT;
133362306a36Sopenharmony_ci	txdctl |= 0x20 << WX_PX_TR_CFG_WTHRESH_SHIFT;
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	/* reinitialize tx_buffer_info */
133662306a36Sopenharmony_ci	memset(ring->tx_buffer_info, 0,
133762306a36Sopenharmony_ci	       sizeof(struct wx_tx_buffer) * ring->count);
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci	/* enable queue */
134062306a36Sopenharmony_ci	wr32(wx, WX_PX_TR_CFG(reg_idx), txdctl);
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	/* poll to verify queue is enabled */
134362306a36Sopenharmony_ci	ret = read_poll_timeout(rd32, txdctl, txdctl & WX_PX_TR_CFG_ENABLE,
134462306a36Sopenharmony_ci				1000, 10000, true, wx, WX_PX_TR_CFG(reg_idx));
134562306a36Sopenharmony_ci	if (ret == -ETIMEDOUT)
134662306a36Sopenharmony_ci		wx_err(wx, "Could not enable Tx Queue %d\n", reg_idx);
134762306a36Sopenharmony_ci}
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_cistatic void wx_configure_rx_ring(struct wx *wx,
135062306a36Sopenharmony_ci				 struct wx_ring *ring)
135162306a36Sopenharmony_ci{
135262306a36Sopenharmony_ci	u16 reg_idx = ring->reg_idx;
135362306a36Sopenharmony_ci	union wx_rx_desc *rx_desc;
135462306a36Sopenharmony_ci	u64 rdba = ring->dma;
135562306a36Sopenharmony_ci	u32 rxdctl;
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	/* disable queue to avoid issues while updating state */
135862306a36Sopenharmony_ci	rxdctl = rd32(wx, WX_PX_RR_CFG(reg_idx));
135962306a36Sopenharmony_ci	wx_disable_rx_queue(wx, ring);
136062306a36Sopenharmony_ci
136162306a36Sopenharmony_ci	wr32(wx, WX_PX_RR_BAL(reg_idx), rdba & DMA_BIT_MASK(32));
136262306a36Sopenharmony_ci	wr32(wx, WX_PX_RR_BAH(reg_idx), upper_32_bits(rdba));
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	if (ring->count == WX_MAX_RXD)
136562306a36Sopenharmony_ci		rxdctl |= 0 << WX_PX_RR_CFG_RR_SIZE_SHIFT;
136662306a36Sopenharmony_ci	else
136762306a36Sopenharmony_ci		rxdctl |= (ring->count / 128) << WX_PX_RR_CFG_RR_SIZE_SHIFT;
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	rxdctl |= 0x1 << WX_PX_RR_CFG_RR_THER_SHIFT;
137062306a36Sopenharmony_ci	wr32(wx, WX_PX_RR_CFG(reg_idx), rxdctl);
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	/* reset head and tail pointers */
137362306a36Sopenharmony_ci	wr32(wx, WX_PX_RR_RP(reg_idx), 0);
137462306a36Sopenharmony_ci	wr32(wx, WX_PX_RR_WP(reg_idx), 0);
137562306a36Sopenharmony_ci	ring->tail = wx->hw_addr + WX_PX_RR_WP(reg_idx);
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	wx_configure_srrctl(wx, ring);
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	/* initialize rx_buffer_info */
138062306a36Sopenharmony_ci	memset(ring->rx_buffer_info, 0,
138162306a36Sopenharmony_ci	       sizeof(struct wx_rx_buffer) * ring->count);
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci	/* initialize Rx descriptor 0 */
138462306a36Sopenharmony_ci	rx_desc = WX_RX_DESC(ring, 0);
138562306a36Sopenharmony_ci	rx_desc->wb.upper.length = 0;
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci	/* enable receive descriptor ring */
138862306a36Sopenharmony_ci	wr32m(wx, WX_PX_RR_CFG(reg_idx),
138962306a36Sopenharmony_ci	      WX_PX_RR_CFG_RR_EN, WX_PX_RR_CFG_RR_EN);
139062306a36Sopenharmony_ci
139162306a36Sopenharmony_ci	wx_enable_rx_queue(wx, ring);
139262306a36Sopenharmony_ci	wx_alloc_rx_buffers(ring, wx_desc_unused(ring));
139362306a36Sopenharmony_ci}
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci/**
139662306a36Sopenharmony_ci * wx_configure_tx - Configure Transmit Unit after Reset
139762306a36Sopenharmony_ci * @wx: pointer to private structure
139862306a36Sopenharmony_ci *
139962306a36Sopenharmony_ci * Configure the Tx unit of the MAC after a reset.
140062306a36Sopenharmony_ci **/
140162306a36Sopenharmony_cistatic void wx_configure_tx(struct wx *wx)
140262306a36Sopenharmony_ci{
140362306a36Sopenharmony_ci	u32 i;
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	/* TDM_CTL.TE must be before Tx queues are enabled */
140662306a36Sopenharmony_ci	wr32m(wx, WX_TDM_CTL,
140762306a36Sopenharmony_ci	      WX_TDM_CTL_TE, WX_TDM_CTL_TE);
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci	/* Setup the HW Tx Head and Tail descriptor pointers */
141062306a36Sopenharmony_ci	for (i = 0; i < wx->num_tx_queues; i++)
141162306a36Sopenharmony_ci		wx_configure_tx_ring(wx, wx->tx_ring[i]);
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	wr32m(wx, WX_TSC_BUF_AE, WX_TSC_BUF_AE_THR, 0x10);
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci	if (wx->mac.type == wx_mac_em)
141662306a36Sopenharmony_ci		wr32m(wx, WX_TSC_CTL, WX_TSC_CTL_TX_DIS | WX_TSC_CTL_TSEC_DIS, 0x1);
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci	/* enable mac transmitter */
141962306a36Sopenharmony_ci	wr32m(wx, WX_MAC_TX_CFG,
142062306a36Sopenharmony_ci	      WX_MAC_TX_CFG_TE, WX_MAC_TX_CFG_TE);
142162306a36Sopenharmony_ci}
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_cistatic void wx_restore_vlan(struct wx *wx)
142462306a36Sopenharmony_ci{
142562306a36Sopenharmony_ci	u16 vid = 1;
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci	wx_vlan_rx_add_vid(wx->netdev, htons(ETH_P_8021Q), 0);
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci	for_each_set_bit_from(vid, wx->active_vlans, VLAN_N_VID)
143062306a36Sopenharmony_ci		wx_vlan_rx_add_vid(wx->netdev, htons(ETH_P_8021Q), vid);
143162306a36Sopenharmony_ci}
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci/**
143462306a36Sopenharmony_ci * wx_configure_rx - Configure Receive Unit after Reset
143562306a36Sopenharmony_ci * @wx: pointer to private structure
143662306a36Sopenharmony_ci *
143762306a36Sopenharmony_ci * Configure the Rx unit of the MAC after a reset.
143862306a36Sopenharmony_ci **/
143962306a36Sopenharmony_civoid wx_configure_rx(struct wx *wx)
144062306a36Sopenharmony_ci{
144162306a36Sopenharmony_ci	u32 psrtype, i;
144262306a36Sopenharmony_ci	int ret;
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	wx_disable_rx(wx);
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_ci	psrtype = WX_RDB_PL_CFG_L4HDR |
144762306a36Sopenharmony_ci		  WX_RDB_PL_CFG_L3HDR |
144862306a36Sopenharmony_ci		  WX_RDB_PL_CFG_L2HDR |
144962306a36Sopenharmony_ci		  WX_RDB_PL_CFG_TUN_TUNHDR;
145062306a36Sopenharmony_ci	wr32(wx, WX_RDB_PL_CFG(0), psrtype);
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ci	/* enable hw crc stripping */
145362306a36Sopenharmony_ci	wr32m(wx, WX_RSC_CTL, WX_RSC_CTL_CRC_STRIP, WX_RSC_CTL_CRC_STRIP);
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	if (wx->mac.type == wx_mac_sp) {
145662306a36Sopenharmony_ci		u32 psrctl;
145762306a36Sopenharmony_ci
145862306a36Sopenharmony_ci		/* RSC Setup */
145962306a36Sopenharmony_ci		psrctl = rd32(wx, WX_PSR_CTL);
146062306a36Sopenharmony_ci		psrctl |= WX_PSR_CTL_RSC_ACK; /* Disable RSC for ACK packets */
146162306a36Sopenharmony_ci		psrctl |= WX_PSR_CTL_RSC_DIS;
146262306a36Sopenharmony_ci		wr32(wx, WX_PSR_CTL, psrctl);
146362306a36Sopenharmony_ci	}
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci	/* set_rx_buffer_len must be called before ring initialization */
146662306a36Sopenharmony_ci	wx_set_rx_buffer_len(wx);
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci	/* Setup the HW Rx Head and Tail Descriptor Pointers and
146962306a36Sopenharmony_ci	 * the Base and Length of the Rx Descriptor Ring
147062306a36Sopenharmony_ci	 */
147162306a36Sopenharmony_ci	for (i = 0; i < wx->num_rx_queues; i++)
147262306a36Sopenharmony_ci		wx_configure_rx_ring(wx, wx->rx_ring[i]);
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci	/* Enable all receives, disable security engine prior to block traffic */
147562306a36Sopenharmony_ci	ret = wx_disable_sec_rx_path(wx);
147662306a36Sopenharmony_ci	if (ret < 0)
147762306a36Sopenharmony_ci		wx_err(wx, "The register status is abnormal, please check device.");
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci	wx_enable_rx(wx);
148062306a36Sopenharmony_ci	wx_enable_sec_rx_path(wx);
148162306a36Sopenharmony_ci}
148262306a36Sopenharmony_ciEXPORT_SYMBOL(wx_configure_rx);
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_cistatic void wx_configure_isb(struct wx *wx)
148562306a36Sopenharmony_ci{
148662306a36Sopenharmony_ci	/* set ISB Address */
148762306a36Sopenharmony_ci	wr32(wx, WX_PX_ISB_ADDR_L, wx->isb_dma & DMA_BIT_MASK(32));
148862306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_ARCH_DMA_ADDR_T_64BIT))
148962306a36Sopenharmony_ci		wr32(wx, WX_PX_ISB_ADDR_H, upper_32_bits(wx->isb_dma));
149062306a36Sopenharmony_ci}
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_civoid wx_configure(struct wx *wx)
149362306a36Sopenharmony_ci{
149462306a36Sopenharmony_ci	wx_set_rxpba(wx);
149562306a36Sopenharmony_ci	wx_configure_port(wx);
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci	wx_set_rx_mode(wx->netdev);
149862306a36Sopenharmony_ci	wx_restore_vlan(wx);
149962306a36Sopenharmony_ci	wx_enable_sec_rx_path(wx);
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_ci	wx_configure_tx(wx);
150262306a36Sopenharmony_ci	wx_configure_rx(wx);
150362306a36Sopenharmony_ci	wx_configure_isb(wx);
150462306a36Sopenharmony_ci}
150562306a36Sopenharmony_ciEXPORT_SYMBOL(wx_configure);
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_ci/**
150862306a36Sopenharmony_ci *  wx_disable_pcie_master - Disable PCI-express master access
150962306a36Sopenharmony_ci *  @wx: pointer to hardware structure
151062306a36Sopenharmony_ci *
151162306a36Sopenharmony_ci *  Disables PCI-Express master access and verifies there are no pending
151262306a36Sopenharmony_ci *  requests.
151362306a36Sopenharmony_ci **/
151462306a36Sopenharmony_ciint wx_disable_pcie_master(struct wx *wx)
151562306a36Sopenharmony_ci{
151662306a36Sopenharmony_ci	int status = 0;
151762306a36Sopenharmony_ci	u32 val;
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ci	/* Always set this bit to ensure any future transactions are blocked */
152062306a36Sopenharmony_ci	pci_clear_master(wx->pdev);
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci	/* Exit if master requests are blocked */
152362306a36Sopenharmony_ci	if (!(rd32(wx, WX_PX_TRANSACTION_PENDING)))
152462306a36Sopenharmony_ci		return 0;
152562306a36Sopenharmony_ci
152662306a36Sopenharmony_ci	/* Poll for master request bit to clear */
152762306a36Sopenharmony_ci	status = read_poll_timeout(rd32, val, !val, 100, WX_PCI_MASTER_DISABLE_TIMEOUT,
152862306a36Sopenharmony_ci				   false, wx, WX_PX_TRANSACTION_PENDING);
152962306a36Sopenharmony_ci	if (status < 0)
153062306a36Sopenharmony_ci		wx_err(wx, "PCIe transaction pending bit did not clear.\n");
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_ci	return status;
153362306a36Sopenharmony_ci}
153462306a36Sopenharmony_ciEXPORT_SYMBOL(wx_disable_pcie_master);
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ci/**
153762306a36Sopenharmony_ci *  wx_stop_adapter - Generic stop Tx/Rx units
153862306a36Sopenharmony_ci *  @wx: pointer to hardware structure
153962306a36Sopenharmony_ci *
154062306a36Sopenharmony_ci *  Sets the adapter_stopped flag within wx_hw struct. Clears interrupts,
154162306a36Sopenharmony_ci *  disables transmit and receive units. The adapter_stopped flag is used by
154262306a36Sopenharmony_ci *  the shared code and drivers to determine if the adapter is in a stopped
154362306a36Sopenharmony_ci *  state and should not touch the hardware.
154462306a36Sopenharmony_ci **/
154562306a36Sopenharmony_ciint wx_stop_adapter(struct wx *wx)
154662306a36Sopenharmony_ci{
154762306a36Sopenharmony_ci	u16 i;
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	/* Set the adapter_stopped flag so other driver functions stop touching
155062306a36Sopenharmony_ci	 * the hardware
155162306a36Sopenharmony_ci	 */
155262306a36Sopenharmony_ci	wx->adapter_stopped = true;
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci	/* Disable the receive unit */
155562306a36Sopenharmony_ci	wx_disable_rx(wx);
155662306a36Sopenharmony_ci
155762306a36Sopenharmony_ci	/* Set interrupt mask to stop interrupts from being generated */
155862306a36Sopenharmony_ci	wx_intr_disable(wx, WX_INTR_ALL);
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ci	/* Clear any pending interrupts, flush previous writes */
156162306a36Sopenharmony_ci	wr32(wx, WX_PX_MISC_IC, 0xffffffff);
156262306a36Sopenharmony_ci	wr32(wx, WX_BME_CTL, 0x3);
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci	/* Disable the transmit unit.  Each queue must be disabled. */
156562306a36Sopenharmony_ci	for (i = 0; i < wx->mac.max_tx_queues; i++) {
156662306a36Sopenharmony_ci		wr32m(wx, WX_PX_TR_CFG(i),
156762306a36Sopenharmony_ci		      WX_PX_TR_CFG_SWFLSH | WX_PX_TR_CFG_ENABLE,
156862306a36Sopenharmony_ci		      WX_PX_TR_CFG_SWFLSH);
156962306a36Sopenharmony_ci	}
157062306a36Sopenharmony_ci
157162306a36Sopenharmony_ci	/* Disable the receive unit by stopping each queue */
157262306a36Sopenharmony_ci	for (i = 0; i < wx->mac.max_rx_queues; i++) {
157362306a36Sopenharmony_ci		wr32m(wx, WX_PX_RR_CFG(i),
157462306a36Sopenharmony_ci		      WX_PX_RR_CFG_RR_EN, 0);
157562306a36Sopenharmony_ci	}
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ci	/* flush all queues disables */
157862306a36Sopenharmony_ci	WX_WRITE_FLUSH(wx);
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci	/* Prevent the PCI-E bus from hanging by disabling PCI-E master
158162306a36Sopenharmony_ci	 * access and verify no pending requests
158262306a36Sopenharmony_ci	 */
158362306a36Sopenharmony_ci	return wx_disable_pcie_master(wx);
158462306a36Sopenharmony_ci}
158562306a36Sopenharmony_ciEXPORT_SYMBOL(wx_stop_adapter);
158662306a36Sopenharmony_ci
158762306a36Sopenharmony_civoid wx_reset_misc(struct wx *wx)
158862306a36Sopenharmony_ci{
158962306a36Sopenharmony_ci	int i;
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci	/* receive packets that size > 2048 */
159262306a36Sopenharmony_ci	wr32m(wx, WX_MAC_RX_CFG, WX_MAC_RX_CFG_JE, WX_MAC_RX_CFG_JE);
159362306a36Sopenharmony_ci
159462306a36Sopenharmony_ci	/* clear counters on read */
159562306a36Sopenharmony_ci	wr32m(wx, WX_MMC_CONTROL,
159662306a36Sopenharmony_ci	      WX_MMC_CONTROL_RSTONRD, WX_MMC_CONTROL_RSTONRD);
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci	wr32m(wx, WX_MAC_RX_FLOW_CTRL,
159962306a36Sopenharmony_ci	      WX_MAC_RX_FLOW_CTRL_RFE, WX_MAC_RX_FLOW_CTRL_RFE);
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci	wr32(wx, WX_MAC_PKT_FLT, WX_MAC_PKT_FLT_PR);
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci	wr32m(wx, WX_MIS_RST_ST,
160462306a36Sopenharmony_ci	      WX_MIS_RST_ST_RST_INIT, 0x1E00);
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_ci	/* errata 4: initialize mng flex tbl and wakeup flex tbl*/
160762306a36Sopenharmony_ci	wr32(wx, WX_PSR_MNG_FLEX_SEL, 0);
160862306a36Sopenharmony_ci	for (i = 0; i < 16; i++) {
160962306a36Sopenharmony_ci		wr32(wx, WX_PSR_MNG_FLEX_DW_L(i), 0);
161062306a36Sopenharmony_ci		wr32(wx, WX_PSR_MNG_FLEX_DW_H(i), 0);
161162306a36Sopenharmony_ci		wr32(wx, WX_PSR_MNG_FLEX_MSK(i), 0);
161262306a36Sopenharmony_ci	}
161362306a36Sopenharmony_ci	wr32(wx, WX_PSR_LAN_FLEX_SEL, 0);
161462306a36Sopenharmony_ci	for (i = 0; i < 16; i++) {
161562306a36Sopenharmony_ci		wr32(wx, WX_PSR_LAN_FLEX_DW_L(i), 0);
161662306a36Sopenharmony_ci		wr32(wx, WX_PSR_LAN_FLEX_DW_H(i), 0);
161762306a36Sopenharmony_ci		wr32(wx, WX_PSR_LAN_FLEX_MSK(i), 0);
161862306a36Sopenharmony_ci	}
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci	/* set pause frame dst mac addr */
162162306a36Sopenharmony_ci	wr32(wx, WX_RDB_PFCMACDAL, 0xC2000001);
162262306a36Sopenharmony_ci	wr32(wx, WX_RDB_PFCMACDAH, 0x0180);
162362306a36Sopenharmony_ci}
162462306a36Sopenharmony_ciEXPORT_SYMBOL(wx_reset_misc);
162562306a36Sopenharmony_ci
162662306a36Sopenharmony_ci/**
162762306a36Sopenharmony_ci *  wx_get_pcie_msix_counts - Gets MSI-X vector count
162862306a36Sopenharmony_ci *  @wx: pointer to hardware structure
162962306a36Sopenharmony_ci *  @msix_count: number of MSI interrupts that can be obtained
163062306a36Sopenharmony_ci *  @max_msix_count: number of MSI interrupts that mac need
163162306a36Sopenharmony_ci *
163262306a36Sopenharmony_ci *  Read PCIe configuration space, and get the MSI-X vector count from
163362306a36Sopenharmony_ci *  the capabilities table.
163462306a36Sopenharmony_ci **/
163562306a36Sopenharmony_ciint wx_get_pcie_msix_counts(struct wx *wx, u16 *msix_count, u16 max_msix_count)
163662306a36Sopenharmony_ci{
163762306a36Sopenharmony_ci	struct pci_dev *pdev = wx->pdev;
163862306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
163962306a36Sopenharmony_ci	int pos;
164062306a36Sopenharmony_ci
164162306a36Sopenharmony_ci	*msix_count = 1;
164262306a36Sopenharmony_ci	pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
164362306a36Sopenharmony_ci	if (!pos) {
164462306a36Sopenharmony_ci		dev_err(dev, "Unable to find MSI-X Capabilities\n");
164562306a36Sopenharmony_ci		return -EINVAL;
164662306a36Sopenharmony_ci	}
164762306a36Sopenharmony_ci	pci_read_config_word(pdev,
164862306a36Sopenharmony_ci			     pos + PCI_MSIX_FLAGS,
164962306a36Sopenharmony_ci			     msix_count);
165062306a36Sopenharmony_ci	*msix_count &= WX_PCIE_MSIX_TBL_SZ_MASK;
165162306a36Sopenharmony_ci	/* MSI-X count is zero-based in HW */
165262306a36Sopenharmony_ci	*msix_count += 1;
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci	if (*msix_count > max_msix_count)
165562306a36Sopenharmony_ci		*msix_count = max_msix_count;
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_ci	return 0;
165862306a36Sopenharmony_ci}
165962306a36Sopenharmony_ciEXPORT_SYMBOL(wx_get_pcie_msix_counts);
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ciint wx_sw_init(struct wx *wx)
166262306a36Sopenharmony_ci{
166362306a36Sopenharmony_ci	struct pci_dev *pdev = wx->pdev;
166462306a36Sopenharmony_ci	u32 ssid = 0;
166562306a36Sopenharmony_ci	int err = 0;
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ci	wx->vendor_id = pdev->vendor;
166862306a36Sopenharmony_ci	wx->device_id = pdev->device;
166962306a36Sopenharmony_ci	wx->revision_id = pdev->revision;
167062306a36Sopenharmony_ci	wx->oem_svid = pdev->subsystem_vendor;
167162306a36Sopenharmony_ci	wx->oem_ssid = pdev->subsystem_device;
167262306a36Sopenharmony_ci	wx->bus.device = PCI_SLOT(pdev->devfn);
167362306a36Sopenharmony_ci	wx->bus.func = PCI_FUNC(pdev->devfn);
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci	if (wx->oem_svid == PCI_VENDOR_ID_WANGXUN) {
167662306a36Sopenharmony_ci		wx->subsystem_vendor_id = pdev->subsystem_vendor;
167762306a36Sopenharmony_ci		wx->subsystem_device_id = pdev->subsystem_device;
167862306a36Sopenharmony_ci	} else {
167962306a36Sopenharmony_ci		err = wx_flash_read_dword(wx, 0xfffdc, &ssid);
168062306a36Sopenharmony_ci		if (err < 0) {
168162306a36Sopenharmony_ci			wx_err(wx, "read of internal subsystem device id failed\n");
168262306a36Sopenharmony_ci			return err;
168362306a36Sopenharmony_ci		}
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_ci		wx->subsystem_device_id = swab16((u16)ssid);
168662306a36Sopenharmony_ci	}
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ci	wx->mac_table = kcalloc(wx->mac.num_rar_entries,
168962306a36Sopenharmony_ci				sizeof(struct wx_mac_addr),
169062306a36Sopenharmony_ci				GFP_KERNEL);
169162306a36Sopenharmony_ci	if (!wx->mac_table) {
169262306a36Sopenharmony_ci		wx_err(wx, "mac_table allocation failed\n");
169362306a36Sopenharmony_ci		return -ENOMEM;
169462306a36Sopenharmony_ci	}
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ci	return 0;
169762306a36Sopenharmony_ci}
169862306a36Sopenharmony_ciEXPORT_SYMBOL(wx_sw_init);
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci/**
170162306a36Sopenharmony_ci *  wx_find_vlvf_slot - find the vlanid or the first empty slot
170262306a36Sopenharmony_ci *  @wx: pointer to hardware structure
170362306a36Sopenharmony_ci *  @vlan: VLAN id to write to VLAN filter
170462306a36Sopenharmony_ci *
170562306a36Sopenharmony_ci *  return the VLVF index where this VLAN id should be placed
170662306a36Sopenharmony_ci *
170762306a36Sopenharmony_ci **/
170862306a36Sopenharmony_cistatic int wx_find_vlvf_slot(struct wx *wx, u32 vlan)
170962306a36Sopenharmony_ci{
171062306a36Sopenharmony_ci	u32 bits = 0, first_empty_slot = 0;
171162306a36Sopenharmony_ci	int regindex;
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci	/* short cut the special case */
171462306a36Sopenharmony_ci	if (vlan == 0)
171562306a36Sopenharmony_ci		return 0;
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_ci	/* Search for the vlan id in the VLVF entries. Save off the first empty
171862306a36Sopenharmony_ci	 * slot found along the way
171962306a36Sopenharmony_ci	 */
172062306a36Sopenharmony_ci	for (regindex = 1; regindex < WX_PSR_VLAN_SWC_ENTRIES; regindex++) {
172162306a36Sopenharmony_ci		wr32(wx, WX_PSR_VLAN_SWC_IDX, regindex);
172262306a36Sopenharmony_ci		bits = rd32(wx, WX_PSR_VLAN_SWC);
172362306a36Sopenharmony_ci		if (!bits && !(first_empty_slot))
172462306a36Sopenharmony_ci			first_empty_slot = regindex;
172562306a36Sopenharmony_ci		else if ((bits & 0x0FFF) == vlan)
172662306a36Sopenharmony_ci			break;
172762306a36Sopenharmony_ci	}
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci	if (regindex >= WX_PSR_VLAN_SWC_ENTRIES) {
173062306a36Sopenharmony_ci		if (first_empty_slot)
173162306a36Sopenharmony_ci			regindex = first_empty_slot;
173262306a36Sopenharmony_ci		else
173362306a36Sopenharmony_ci			regindex = -ENOMEM;
173462306a36Sopenharmony_ci	}
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_ci	return regindex;
173762306a36Sopenharmony_ci}
173862306a36Sopenharmony_ci
173962306a36Sopenharmony_ci/**
174062306a36Sopenharmony_ci *  wx_set_vlvf - Set VLAN Pool Filter
174162306a36Sopenharmony_ci *  @wx: pointer to hardware structure
174262306a36Sopenharmony_ci *  @vlan: VLAN id to write to VLAN filter
174362306a36Sopenharmony_ci *  @vind: VMDq output index that maps queue to VLAN id in VFVFB
174462306a36Sopenharmony_ci *  @vlan_on: boolean flag to turn on/off VLAN in VFVF
174562306a36Sopenharmony_ci *  @vfta_changed: pointer to boolean flag which indicates whether VFTA
174662306a36Sopenharmony_ci *                 should be changed
174762306a36Sopenharmony_ci *
174862306a36Sopenharmony_ci *  Turn on/off specified bit in VLVF table.
174962306a36Sopenharmony_ci **/
175062306a36Sopenharmony_cistatic int wx_set_vlvf(struct wx *wx, u32 vlan, u32 vind, bool vlan_on,
175162306a36Sopenharmony_ci		       bool *vfta_changed)
175262306a36Sopenharmony_ci{
175362306a36Sopenharmony_ci	int vlvf_index;
175462306a36Sopenharmony_ci	u32 vt, bits;
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_ci	/* If VT Mode is set
175762306a36Sopenharmony_ci	 *   Either vlan_on
175862306a36Sopenharmony_ci	 *     make sure the vlan is in VLVF
175962306a36Sopenharmony_ci	 *     set the vind bit in the matching VLVFB
176062306a36Sopenharmony_ci	 *   Or !vlan_on
176162306a36Sopenharmony_ci	 *     clear the pool bit and possibly the vind
176262306a36Sopenharmony_ci	 */
176362306a36Sopenharmony_ci	vt = rd32(wx, WX_CFG_PORT_CTL);
176462306a36Sopenharmony_ci	if (!(vt & WX_CFG_PORT_CTL_NUM_VT_MASK))
176562306a36Sopenharmony_ci		return 0;
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_ci	vlvf_index = wx_find_vlvf_slot(wx, vlan);
176862306a36Sopenharmony_ci	if (vlvf_index < 0)
176962306a36Sopenharmony_ci		return vlvf_index;
177062306a36Sopenharmony_ci
177162306a36Sopenharmony_ci	wr32(wx, WX_PSR_VLAN_SWC_IDX, vlvf_index);
177262306a36Sopenharmony_ci	if (vlan_on) {
177362306a36Sopenharmony_ci		/* set the pool bit */
177462306a36Sopenharmony_ci		if (vind < 32) {
177562306a36Sopenharmony_ci			bits = rd32(wx, WX_PSR_VLAN_SWC_VM_L);
177662306a36Sopenharmony_ci			bits |= (1 << vind);
177762306a36Sopenharmony_ci			wr32(wx, WX_PSR_VLAN_SWC_VM_L, bits);
177862306a36Sopenharmony_ci		} else {
177962306a36Sopenharmony_ci			bits = rd32(wx, WX_PSR_VLAN_SWC_VM_H);
178062306a36Sopenharmony_ci			bits |= (1 << (vind - 32));
178162306a36Sopenharmony_ci			wr32(wx, WX_PSR_VLAN_SWC_VM_H, bits);
178262306a36Sopenharmony_ci		}
178362306a36Sopenharmony_ci	} else {
178462306a36Sopenharmony_ci		/* clear the pool bit */
178562306a36Sopenharmony_ci		if (vind < 32) {
178662306a36Sopenharmony_ci			bits = rd32(wx, WX_PSR_VLAN_SWC_VM_L);
178762306a36Sopenharmony_ci			bits &= ~(1 << vind);
178862306a36Sopenharmony_ci			wr32(wx, WX_PSR_VLAN_SWC_VM_L, bits);
178962306a36Sopenharmony_ci			bits |= rd32(wx, WX_PSR_VLAN_SWC_VM_H);
179062306a36Sopenharmony_ci		} else {
179162306a36Sopenharmony_ci			bits = rd32(wx, WX_PSR_VLAN_SWC_VM_H);
179262306a36Sopenharmony_ci			bits &= ~(1 << (vind - 32));
179362306a36Sopenharmony_ci			wr32(wx, WX_PSR_VLAN_SWC_VM_H, bits);
179462306a36Sopenharmony_ci			bits |= rd32(wx, WX_PSR_VLAN_SWC_VM_L);
179562306a36Sopenharmony_ci		}
179662306a36Sopenharmony_ci	}
179762306a36Sopenharmony_ci
179862306a36Sopenharmony_ci	if (bits) {
179962306a36Sopenharmony_ci		wr32(wx, WX_PSR_VLAN_SWC, (WX_PSR_VLAN_SWC_VIEN | vlan));
180062306a36Sopenharmony_ci		if (!vlan_on && vfta_changed)
180162306a36Sopenharmony_ci			*vfta_changed = false;
180262306a36Sopenharmony_ci	} else {
180362306a36Sopenharmony_ci		wr32(wx, WX_PSR_VLAN_SWC, 0);
180462306a36Sopenharmony_ci	}
180562306a36Sopenharmony_ci
180662306a36Sopenharmony_ci	return 0;
180762306a36Sopenharmony_ci}
180862306a36Sopenharmony_ci
180962306a36Sopenharmony_ci/**
181062306a36Sopenharmony_ci *  wx_set_vfta - Set VLAN filter table
181162306a36Sopenharmony_ci *  @wx: pointer to hardware structure
181262306a36Sopenharmony_ci *  @vlan: VLAN id to write to VLAN filter
181362306a36Sopenharmony_ci *  @vind: VMDq output index that maps queue to VLAN id in VFVFB
181462306a36Sopenharmony_ci *  @vlan_on: boolean flag to turn on/off VLAN in VFVF
181562306a36Sopenharmony_ci *
181662306a36Sopenharmony_ci *  Turn on/off specified VLAN in the VLAN filter table.
181762306a36Sopenharmony_ci **/
181862306a36Sopenharmony_cistatic int wx_set_vfta(struct wx *wx, u32 vlan, u32 vind, bool vlan_on)
181962306a36Sopenharmony_ci{
182062306a36Sopenharmony_ci	u32 bitindex, vfta, targetbit;
182162306a36Sopenharmony_ci	bool vfta_changed = false;
182262306a36Sopenharmony_ci	int regindex, ret;
182362306a36Sopenharmony_ci
182462306a36Sopenharmony_ci	/* this is a 2 part operation - first the VFTA, then the
182562306a36Sopenharmony_ci	 * VLVF and VLVFB if VT Mode is set
182662306a36Sopenharmony_ci	 * We don't write the VFTA until we know the VLVF part succeeded.
182762306a36Sopenharmony_ci	 */
182862306a36Sopenharmony_ci
182962306a36Sopenharmony_ci	/* Part 1
183062306a36Sopenharmony_ci	 * The VFTA is a bitstring made up of 128 32-bit registers
183162306a36Sopenharmony_ci	 * that enable the particular VLAN id, much like the MTA:
183262306a36Sopenharmony_ci	 *    bits[11-5]: which register
183362306a36Sopenharmony_ci	 *    bits[4-0]:  which bit in the register
183462306a36Sopenharmony_ci	 */
183562306a36Sopenharmony_ci	regindex = (vlan >> 5) & 0x7F;
183662306a36Sopenharmony_ci	bitindex = vlan & 0x1F;
183762306a36Sopenharmony_ci	targetbit = (1 << bitindex);
183862306a36Sopenharmony_ci	/* errata 5 */
183962306a36Sopenharmony_ci	vfta = wx->mac.vft_shadow[regindex];
184062306a36Sopenharmony_ci	if (vlan_on) {
184162306a36Sopenharmony_ci		if (!(vfta & targetbit)) {
184262306a36Sopenharmony_ci			vfta |= targetbit;
184362306a36Sopenharmony_ci			vfta_changed = true;
184462306a36Sopenharmony_ci		}
184562306a36Sopenharmony_ci	} else {
184662306a36Sopenharmony_ci		if ((vfta & targetbit)) {
184762306a36Sopenharmony_ci			vfta &= ~targetbit;
184862306a36Sopenharmony_ci			vfta_changed = true;
184962306a36Sopenharmony_ci		}
185062306a36Sopenharmony_ci	}
185162306a36Sopenharmony_ci	/* Part 2
185262306a36Sopenharmony_ci	 * Call wx_set_vlvf to set VLVFB and VLVF
185362306a36Sopenharmony_ci	 */
185462306a36Sopenharmony_ci	ret = wx_set_vlvf(wx, vlan, vind, vlan_on, &vfta_changed);
185562306a36Sopenharmony_ci	if (ret != 0)
185662306a36Sopenharmony_ci		return ret;
185762306a36Sopenharmony_ci
185862306a36Sopenharmony_ci	if (vfta_changed)
185962306a36Sopenharmony_ci		wr32(wx, WX_PSR_VLAN_TBL(regindex), vfta);
186062306a36Sopenharmony_ci	wx->mac.vft_shadow[regindex] = vfta;
186162306a36Sopenharmony_ci
186262306a36Sopenharmony_ci	return 0;
186362306a36Sopenharmony_ci}
186462306a36Sopenharmony_ci
186562306a36Sopenharmony_ci/**
186662306a36Sopenharmony_ci *  wx_clear_vfta - Clear VLAN filter table
186762306a36Sopenharmony_ci *  @wx: pointer to hardware structure
186862306a36Sopenharmony_ci *
186962306a36Sopenharmony_ci *  Clears the VLAN filer table, and the VMDq index associated with the filter
187062306a36Sopenharmony_ci **/
187162306a36Sopenharmony_cistatic void wx_clear_vfta(struct wx *wx)
187262306a36Sopenharmony_ci{
187362306a36Sopenharmony_ci	u32 offset;
187462306a36Sopenharmony_ci
187562306a36Sopenharmony_ci	for (offset = 0; offset < wx->mac.vft_size; offset++) {
187662306a36Sopenharmony_ci		wr32(wx, WX_PSR_VLAN_TBL(offset), 0);
187762306a36Sopenharmony_ci		wx->mac.vft_shadow[offset] = 0;
187862306a36Sopenharmony_ci	}
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_ci	for (offset = 0; offset < WX_PSR_VLAN_SWC_ENTRIES; offset++) {
188162306a36Sopenharmony_ci		wr32(wx, WX_PSR_VLAN_SWC_IDX, offset);
188262306a36Sopenharmony_ci		wr32(wx, WX_PSR_VLAN_SWC, 0);
188362306a36Sopenharmony_ci		wr32(wx, WX_PSR_VLAN_SWC_VM_L, 0);
188462306a36Sopenharmony_ci		wr32(wx, WX_PSR_VLAN_SWC_VM_H, 0);
188562306a36Sopenharmony_ci	}
188662306a36Sopenharmony_ci}
188762306a36Sopenharmony_ci
188862306a36Sopenharmony_ciint wx_vlan_rx_add_vid(struct net_device *netdev,
188962306a36Sopenharmony_ci		       __be16 proto, u16 vid)
189062306a36Sopenharmony_ci{
189162306a36Sopenharmony_ci	struct wx *wx = netdev_priv(netdev);
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_ci	/* add VID to filter table */
189462306a36Sopenharmony_ci	wx_set_vfta(wx, vid, VMDQ_P(0), true);
189562306a36Sopenharmony_ci	set_bit(vid, wx->active_vlans);
189662306a36Sopenharmony_ci
189762306a36Sopenharmony_ci	return 0;
189862306a36Sopenharmony_ci}
189962306a36Sopenharmony_ciEXPORT_SYMBOL(wx_vlan_rx_add_vid);
190062306a36Sopenharmony_ci
190162306a36Sopenharmony_ciint wx_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid)
190262306a36Sopenharmony_ci{
190362306a36Sopenharmony_ci	struct wx *wx = netdev_priv(netdev);
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci	/* remove VID from filter table */
190662306a36Sopenharmony_ci	if (vid)
190762306a36Sopenharmony_ci		wx_set_vfta(wx, vid, VMDQ_P(0), false);
190862306a36Sopenharmony_ci	clear_bit(vid, wx->active_vlans);
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ci	return 0;
191162306a36Sopenharmony_ci}
191262306a36Sopenharmony_ciEXPORT_SYMBOL(wx_vlan_rx_kill_vid);
191362306a36Sopenharmony_ci
191462306a36Sopenharmony_ci/**
191562306a36Sopenharmony_ci *  wx_start_hw - Prepare hardware for Tx/Rx
191662306a36Sopenharmony_ci *  @wx: pointer to hardware structure
191762306a36Sopenharmony_ci *
191862306a36Sopenharmony_ci *  Starts the hardware using the generic start_hw function
191962306a36Sopenharmony_ci *  and the generation start_hw function.
192062306a36Sopenharmony_ci *  Then performs revision-specific operations, if any.
192162306a36Sopenharmony_ci **/
192262306a36Sopenharmony_civoid wx_start_hw(struct wx *wx)
192362306a36Sopenharmony_ci{
192462306a36Sopenharmony_ci	int i;
192562306a36Sopenharmony_ci
192662306a36Sopenharmony_ci	/* Clear the VLAN filter table */
192762306a36Sopenharmony_ci	wx_clear_vfta(wx);
192862306a36Sopenharmony_ci	WX_WRITE_FLUSH(wx);
192962306a36Sopenharmony_ci	/* Clear the rate limiters */
193062306a36Sopenharmony_ci	for (i = 0; i < wx->mac.max_tx_queues; i++) {
193162306a36Sopenharmony_ci		wr32(wx, WX_TDM_RP_IDX, i);
193262306a36Sopenharmony_ci		wr32(wx, WX_TDM_RP_RATE, 0);
193362306a36Sopenharmony_ci	}
193462306a36Sopenharmony_ci}
193562306a36Sopenharmony_ciEXPORT_SYMBOL(wx_start_hw);
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_ciMODULE_LICENSE("GPL");
1938