162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * QLogic qlcnic NIC Driver
462306a36Sopenharmony_ci * Copyright (c) 2009-2013 QLogic Corporation
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/slab.h>
862306a36Sopenharmony_ci#include <net/ip.h>
962306a36Sopenharmony_ci#include <linux/bitops.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include "qlcnic.h"
1262306a36Sopenharmony_ci#include "qlcnic_hdr.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#define MASK(n) ((1ULL<<(n))-1)
1562306a36Sopenharmony_ci#define OCM_WIN_P3P(addr) (addr & 0xffc0000)
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#define GET_MEM_OFFS_2M(addr) (addr & MASK(18))
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#define CRB_BLK(off)	((off >> 20) & 0x3f)
2062306a36Sopenharmony_ci#define CRB_SUBBLK(off)	((off >> 16) & 0xf)
2162306a36Sopenharmony_ci#define CRB_WINDOW_2M	(0x130060)
2262306a36Sopenharmony_ci#define CRB_HI(off)	((crb_hub_agt[CRB_BLK(off)] << 20) | ((off) & 0xf0000))
2362306a36Sopenharmony_ci#define CRB_INDIRECT_2M	(0x1e0000UL)
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistruct qlcnic_ms_reg_ctrl {
2662306a36Sopenharmony_ci	u32 ocm_window;
2762306a36Sopenharmony_ci	u32 control;
2862306a36Sopenharmony_ci	u32 hi;
2962306a36Sopenharmony_ci	u32 low;
3062306a36Sopenharmony_ci	u32 rd[4];
3162306a36Sopenharmony_ci	u32 wd[4];
3262306a36Sopenharmony_ci	u64 off;
3362306a36Sopenharmony_ci};
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#ifndef readq
3662306a36Sopenharmony_cistatic inline u64 readq(void __iomem *addr)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	return readl(addr) | (((u64) readl(addr + 4)) << 32LL);
3962306a36Sopenharmony_ci}
4062306a36Sopenharmony_ci#endif
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#ifndef writeq
4362306a36Sopenharmony_cistatic inline void writeq(u64 val, void __iomem *addr)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	writel(((u32) (val)), (addr));
4662306a36Sopenharmony_ci	writel(((u32) (val >> 32)), (addr + 4));
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ci#endif
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic struct crb_128M_2M_block_map
5162306a36Sopenharmony_cicrb_128M_2M_map[64] __cacheline_aligned_in_smp = {
5262306a36Sopenharmony_ci    {{{0, 0,         0,         0} } },		/* 0: PCI */
5362306a36Sopenharmony_ci    {{{1, 0x0100000, 0x0102000, 0x120000},	/* 1: PCIE */
5462306a36Sopenharmony_ci	  {1, 0x0110000, 0x0120000, 0x130000},
5562306a36Sopenharmony_ci	  {1, 0x0120000, 0x0122000, 0x124000},
5662306a36Sopenharmony_ci	  {1, 0x0130000, 0x0132000, 0x126000},
5762306a36Sopenharmony_ci	  {1, 0x0140000, 0x0142000, 0x128000},
5862306a36Sopenharmony_ci	  {1, 0x0150000, 0x0152000, 0x12a000},
5962306a36Sopenharmony_ci	  {1, 0x0160000, 0x0170000, 0x110000},
6062306a36Sopenharmony_ci	  {1, 0x0170000, 0x0172000, 0x12e000},
6162306a36Sopenharmony_ci	  {0, 0x0000000, 0x0000000, 0x000000},
6262306a36Sopenharmony_ci	  {0, 0x0000000, 0x0000000, 0x000000},
6362306a36Sopenharmony_ci	  {0, 0x0000000, 0x0000000, 0x000000},
6462306a36Sopenharmony_ci	  {0, 0x0000000, 0x0000000, 0x000000},
6562306a36Sopenharmony_ci	  {0, 0x0000000, 0x0000000, 0x000000},
6662306a36Sopenharmony_ci	  {0, 0x0000000, 0x0000000, 0x000000},
6762306a36Sopenharmony_ci	  {1, 0x01e0000, 0x01e0800, 0x122000},
6862306a36Sopenharmony_ci	  {0, 0x0000000, 0x0000000, 0x000000} } },
6962306a36Sopenharmony_ci	{{{1, 0x0200000, 0x0210000, 0x180000} } },/* 2: MN */
7062306a36Sopenharmony_ci    {{{0, 0,         0,         0} } },	    /* 3: */
7162306a36Sopenharmony_ci    {{{1, 0x0400000, 0x0401000, 0x169000} } },/* 4: P2NR1 */
7262306a36Sopenharmony_ci    {{{1, 0x0500000, 0x0510000, 0x140000} } },/* 5: SRE   */
7362306a36Sopenharmony_ci    {{{1, 0x0600000, 0x0610000, 0x1c0000} } },/* 6: NIU   */
7462306a36Sopenharmony_ci    {{{1, 0x0700000, 0x0704000, 0x1b8000} } },/* 7: QM    */
7562306a36Sopenharmony_ci    {{{1, 0x0800000, 0x0802000, 0x170000},  /* 8: SQM0  */
7662306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
7762306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
7862306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
7962306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
8062306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
8162306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
8262306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
8362306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
8462306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
8562306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
8662306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
8762306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
8862306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
8962306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
9062306a36Sopenharmony_ci      {1, 0x08f0000, 0x08f2000, 0x172000} } },
9162306a36Sopenharmony_ci    {{{1, 0x0900000, 0x0902000, 0x174000},	/* 9: SQM1*/
9262306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
9362306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
9462306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
9562306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
9662306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
9762306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
9862306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
9962306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
10062306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
10162306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
10262306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
10362306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
10462306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
10562306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
10662306a36Sopenharmony_ci      {1, 0x09f0000, 0x09f2000, 0x176000} } },
10762306a36Sopenharmony_ci    {{{0, 0x0a00000, 0x0a02000, 0x178000},	/* 10: SQM2*/
10862306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
10962306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
11062306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
11162306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
11262306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
11362306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
11462306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
11562306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
11662306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
11762306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
11862306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
11962306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
12062306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
12162306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
12262306a36Sopenharmony_ci      {1, 0x0af0000, 0x0af2000, 0x17a000} } },
12362306a36Sopenharmony_ci    {{{0, 0x0b00000, 0x0b02000, 0x17c000},	/* 11: SQM3*/
12462306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
12562306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
12662306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
12762306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
12862306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
12962306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
13062306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
13162306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
13262306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
13362306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
13462306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
13562306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
13662306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
13762306a36Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
13862306a36Sopenharmony_ci      {1, 0x0bf0000, 0x0bf2000, 0x17e000} } },
13962306a36Sopenharmony_ci	{{{1, 0x0c00000, 0x0c04000, 0x1d4000} } },/* 12: I2Q */
14062306a36Sopenharmony_ci	{{{1, 0x0d00000, 0x0d04000, 0x1a4000} } },/* 13: TMR */
14162306a36Sopenharmony_ci	{{{1, 0x0e00000, 0x0e04000, 0x1a0000} } },/* 14: ROMUSB */
14262306a36Sopenharmony_ci	{{{1, 0x0f00000, 0x0f01000, 0x164000} } },/* 15: PEG4 */
14362306a36Sopenharmony_ci	{{{0, 0x1000000, 0x1004000, 0x1a8000} } },/* 16: XDMA */
14462306a36Sopenharmony_ci	{{{1, 0x1100000, 0x1101000, 0x160000} } },/* 17: PEG0 */
14562306a36Sopenharmony_ci	{{{1, 0x1200000, 0x1201000, 0x161000} } },/* 18: PEG1 */
14662306a36Sopenharmony_ci	{{{1, 0x1300000, 0x1301000, 0x162000} } },/* 19: PEG2 */
14762306a36Sopenharmony_ci	{{{1, 0x1400000, 0x1401000, 0x163000} } },/* 20: PEG3 */
14862306a36Sopenharmony_ci	{{{1, 0x1500000, 0x1501000, 0x165000} } },/* 21: P2ND */
14962306a36Sopenharmony_ci	{{{1, 0x1600000, 0x1601000, 0x166000} } },/* 22: P2NI */
15062306a36Sopenharmony_ci	{{{0, 0,         0,         0} } },	/* 23: */
15162306a36Sopenharmony_ci	{{{0, 0,         0,         0} } },	/* 24: */
15262306a36Sopenharmony_ci	{{{0, 0,         0,         0} } },	/* 25: */
15362306a36Sopenharmony_ci	{{{0, 0,         0,         0} } },	/* 26: */
15462306a36Sopenharmony_ci	{{{0, 0,         0,         0} } },	/* 27: */
15562306a36Sopenharmony_ci	{{{0, 0,         0,         0} } },	/* 28: */
15662306a36Sopenharmony_ci	{{{1, 0x1d00000, 0x1d10000, 0x190000} } },/* 29: MS */
15762306a36Sopenharmony_ci    {{{1, 0x1e00000, 0x1e01000, 0x16a000} } },/* 30: P2NR2 */
15862306a36Sopenharmony_ci    {{{1, 0x1f00000, 0x1f10000, 0x150000} } },/* 31: EPG */
15962306a36Sopenharmony_ci	{{{0} } },				/* 32: PCI */
16062306a36Sopenharmony_ci	{{{1, 0x2100000, 0x2102000, 0x120000},	/* 33: PCIE */
16162306a36Sopenharmony_ci	  {1, 0x2110000, 0x2120000, 0x130000},
16262306a36Sopenharmony_ci	  {1, 0x2120000, 0x2122000, 0x124000},
16362306a36Sopenharmony_ci	  {1, 0x2130000, 0x2132000, 0x126000},
16462306a36Sopenharmony_ci	  {1, 0x2140000, 0x2142000, 0x128000},
16562306a36Sopenharmony_ci	  {1, 0x2150000, 0x2152000, 0x12a000},
16662306a36Sopenharmony_ci	  {1, 0x2160000, 0x2170000, 0x110000},
16762306a36Sopenharmony_ci	  {1, 0x2170000, 0x2172000, 0x12e000},
16862306a36Sopenharmony_ci	  {0, 0x0000000, 0x0000000, 0x000000},
16962306a36Sopenharmony_ci	  {0, 0x0000000, 0x0000000, 0x000000},
17062306a36Sopenharmony_ci	  {0, 0x0000000, 0x0000000, 0x000000},
17162306a36Sopenharmony_ci	  {0, 0x0000000, 0x0000000, 0x000000},
17262306a36Sopenharmony_ci	  {0, 0x0000000, 0x0000000, 0x000000},
17362306a36Sopenharmony_ci	  {0, 0x0000000, 0x0000000, 0x000000},
17462306a36Sopenharmony_ci	  {0, 0x0000000, 0x0000000, 0x000000},
17562306a36Sopenharmony_ci	  {0, 0x0000000, 0x0000000, 0x000000} } },
17662306a36Sopenharmony_ci	{{{1, 0x2200000, 0x2204000, 0x1b0000} } },/* 34: CAM */
17762306a36Sopenharmony_ci	{{{0} } },				/* 35: */
17862306a36Sopenharmony_ci	{{{0} } },				/* 36: */
17962306a36Sopenharmony_ci	{{{0} } },				/* 37: */
18062306a36Sopenharmony_ci	{{{0} } },				/* 38: */
18162306a36Sopenharmony_ci	{{{0} } },				/* 39: */
18262306a36Sopenharmony_ci	{{{1, 0x2800000, 0x2804000, 0x1a4000} } },/* 40: TMR */
18362306a36Sopenharmony_ci	{{{1, 0x2900000, 0x2901000, 0x16b000} } },/* 41: P2NR3 */
18462306a36Sopenharmony_ci	{{{1, 0x2a00000, 0x2a00400, 0x1ac400} } },/* 42: RPMX1 */
18562306a36Sopenharmony_ci	{{{1, 0x2b00000, 0x2b00400, 0x1ac800} } },/* 43: RPMX2 */
18662306a36Sopenharmony_ci	{{{1, 0x2c00000, 0x2c00400, 0x1acc00} } },/* 44: RPMX3 */
18762306a36Sopenharmony_ci	{{{1, 0x2d00000, 0x2d00400, 0x1ad000} } },/* 45: RPMX4 */
18862306a36Sopenharmony_ci	{{{1, 0x2e00000, 0x2e00400, 0x1ad400} } },/* 46: RPMX5 */
18962306a36Sopenharmony_ci	{{{1, 0x2f00000, 0x2f00400, 0x1ad800} } },/* 47: RPMX6 */
19062306a36Sopenharmony_ci	{{{1, 0x3000000, 0x3000400, 0x1adc00} } },/* 48: RPMX7 */
19162306a36Sopenharmony_ci	{{{0, 0x3100000, 0x3104000, 0x1a8000} } },/* 49: XDMA */
19262306a36Sopenharmony_ci	{{{1, 0x3200000, 0x3204000, 0x1d4000} } },/* 50: I2Q */
19362306a36Sopenharmony_ci	{{{1, 0x3300000, 0x3304000, 0x1a0000} } },/* 51: ROMUSB */
19462306a36Sopenharmony_ci	{{{0} } },				/* 52: */
19562306a36Sopenharmony_ci	{{{1, 0x3500000, 0x3500400, 0x1ac000} } },/* 53: RPMX0 */
19662306a36Sopenharmony_ci	{{{1, 0x3600000, 0x3600400, 0x1ae000} } },/* 54: RPMX8 */
19762306a36Sopenharmony_ci	{{{1, 0x3700000, 0x3700400, 0x1ae400} } },/* 55: RPMX9 */
19862306a36Sopenharmony_ci	{{{1, 0x3800000, 0x3804000, 0x1d0000} } },/* 56: OCM0 */
19962306a36Sopenharmony_ci	{{{1, 0x3900000, 0x3904000, 0x1b4000} } },/* 57: CRYPTO */
20062306a36Sopenharmony_ci	{{{1, 0x3a00000, 0x3a04000, 0x1d8000} } },/* 58: SMB */
20162306a36Sopenharmony_ci	{{{0} } },				/* 59: I2C0 */
20262306a36Sopenharmony_ci	{{{0} } },				/* 60: I2C1 */
20362306a36Sopenharmony_ci	{{{1, 0x3d00000, 0x3d04000, 0x1d8000} } },/* 61: LPC */
20462306a36Sopenharmony_ci	{{{1, 0x3e00000, 0x3e01000, 0x167000} } },/* 62: P2NC */
20562306a36Sopenharmony_ci	{{{1, 0x3f00000, 0x3f01000, 0x168000} } }	/* 63: P2NR0 */
20662306a36Sopenharmony_ci};
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci/*
20962306a36Sopenharmony_ci * top 12 bits of crb internal address (hub, agent)
21062306a36Sopenharmony_ci */
21162306a36Sopenharmony_cistatic const unsigned crb_hub_agt[64] = {
21262306a36Sopenharmony_ci	0,
21362306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_PS,
21462306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_MN,
21562306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_MS,
21662306a36Sopenharmony_ci	0,
21762306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_SRE,
21862306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_NIU,
21962306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_QMN,
22062306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_SQN0,
22162306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_SQN1,
22262306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_SQN2,
22362306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_SQN3,
22462306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_I2Q,
22562306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_TIMR,
22662306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_ROMUSB,
22762306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_PGN4,
22862306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_XDMA,
22962306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_PGN0,
23062306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_PGN1,
23162306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_PGN2,
23262306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_PGN3,
23362306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_PGND,
23462306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_PGNI,
23562306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_PGS0,
23662306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_PGS1,
23762306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_PGS2,
23862306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_PGS3,
23962306a36Sopenharmony_ci	0,
24062306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_PGSI,
24162306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_SN,
24262306a36Sopenharmony_ci	0,
24362306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_EG,
24462306a36Sopenharmony_ci	0,
24562306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_PS,
24662306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_CAM,
24762306a36Sopenharmony_ci	0,
24862306a36Sopenharmony_ci	0,
24962306a36Sopenharmony_ci	0,
25062306a36Sopenharmony_ci	0,
25162306a36Sopenharmony_ci	0,
25262306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_TIMR,
25362306a36Sopenharmony_ci	0,
25462306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX1,
25562306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX2,
25662306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX3,
25762306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX4,
25862306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX5,
25962306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX6,
26062306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX7,
26162306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_XDMA,
26262306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_I2Q,
26362306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_ROMUSB,
26462306a36Sopenharmony_ci	0,
26562306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX0,
26662306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX8,
26762306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX9,
26862306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_OCM0,
26962306a36Sopenharmony_ci	0,
27062306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_SMB,
27162306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_I2C0,
27262306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_I2C1,
27362306a36Sopenharmony_ci	0,
27462306a36Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_PGNC,
27562306a36Sopenharmony_ci	0,
27662306a36Sopenharmony_ci};
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci/*  PCI Windowing for DDR regions.  */
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci#define QLCNIC_PCIE_SEM_TIMEOUT	10000
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cistatic void qlcnic_read_window_reg(u32 addr, void __iomem *bar0, u32 *data)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	u32 dest;
28562306a36Sopenharmony_ci	void __iomem *val;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	dest = addr & 0xFFFF0000;
28862306a36Sopenharmony_ci	val = bar0 + QLCNIC_FW_DUMP_REG1;
28962306a36Sopenharmony_ci	writel(dest, val);
29062306a36Sopenharmony_ci	readl(val);
29162306a36Sopenharmony_ci	val = bar0 + QLCNIC_FW_DUMP_REG2 + LSW(addr);
29262306a36Sopenharmony_ci	*data = readl(val);
29362306a36Sopenharmony_ci}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_cistatic void qlcnic_write_window_reg(u32 addr, void __iomem *bar0, u32 data)
29662306a36Sopenharmony_ci{
29762306a36Sopenharmony_ci	u32 dest;
29862306a36Sopenharmony_ci	void __iomem *val;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	dest = addr & 0xFFFF0000;
30162306a36Sopenharmony_ci	val = bar0 + QLCNIC_FW_DUMP_REG1;
30262306a36Sopenharmony_ci	writel(dest, val);
30362306a36Sopenharmony_ci	readl(val);
30462306a36Sopenharmony_ci	val = bar0 + QLCNIC_FW_DUMP_REG2 + LSW(addr);
30562306a36Sopenharmony_ci	writel(data, val);
30662306a36Sopenharmony_ci	readl(val);
30762306a36Sopenharmony_ci}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ciint
31062306a36Sopenharmony_ciqlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg)
31162306a36Sopenharmony_ci{
31262306a36Sopenharmony_ci	int timeout = 0, err = 0, done = 0;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	while (!done) {
31562306a36Sopenharmony_ci		done = QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_LOCK(sem)),
31662306a36Sopenharmony_ci			       &err);
31762306a36Sopenharmony_ci		if (done == 1)
31862306a36Sopenharmony_ci			break;
31962306a36Sopenharmony_ci		if (++timeout >= QLCNIC_PCIE_SEM_TIMEOUT) {
32062306a36Sopenharmony_ci			if (id_reg) {
32162306a36Sopenharmony_ci				done = QLCRD32(adapter, id_reg, &err);
32262306a36Sopenharmony_ci				if (done != -1)
32362306a36Sopenharmony_ci					dev_err(&adapter->pdev->dev,
32462306a36Sopenharmony_ci						"Failed to acquire sem=%d lock held by=%d\n",
32562306a36Sopenharmony_ci						sem, done);
32662306a36Sopenharmony_ci				else
32762306a36Sopenharmony_ci					dev_err(&adapter->pdev->dev,
32862306a36Sopenharmony_ci						"Failed to acquire sem=%d lock",
32962306a36Sopenharmony_ci						sem);
33062306a36Sopenharmony_ci			} else {
33162306a36Sopenharmony_ci				dev_err(&adapter->pdev->dev,
33262306a36Sopenharmony_ci					"Failed to acquire sem=%d lock", sem);
33362306a36Sopenharmony_ci			}
33462306a36Sopenharmony_ci			return -EIO;
33562306a36Sopenharmony_ci		}
33662306a36Sopenharmony_ci		udelay(1200);
33762306a36Sopenharmony_ci	}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	if (id_reg)
34062306a36Sopenharmony_ci		QLCWR32(adapter, id_reg, adapter->portnum);
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	return 0;
34362306a36Sopenharmony_ci}
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_civoid
34662306a36Sopenharmony_ciqlcnic_pcie_sem_unlock(struct qlcnic_adapter *adapter, int sem)
34762306a36Sopenharmony_ci{
34862306a36Sopenharmony_ci	int err = 0;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_UNLOCK(sem)), &err);
35162306a36Sopenharmony_ci}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ciint qlcnic_ind_rd(struct qlcnic_adapter *adapter, u32 addr)
35462306a36Sopenharmony_ci{
35562306a36Sopenharmony_ci	int err = 0;
35662306a36Sopenharmony_ci	u32 data;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	if (qlcnic_82xx_check(adapter))
35962306a36Sopenharmony_ci		qlcnic_read_window_reg(addr, adapter->ahw->pci_base0, &data);
36062306a36Sopenharmony_ci	else {
36162306a36Sopenharmony_ci		data = QLCRD32(adapter, addr, &err);
36262306a36Sopenharmony_ci		if (err == -EIO)
36362306a36Sopenharmony_ci			return err;
36462306a36Sopenharmony_ci	}
36562306a36Sopenharmony_ci	return data;
36662306a36Sopenharmony_ci}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ciint qlcnic_ind_wr(struct qlcnic_adapter *adapter, u32 addr, u32 data)
36962306a36Sopenharmony_ci{
37062306a36Sopenharmony_ci	int ret = 0;
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	if (qlcnic_82xx_check(adapter))
37362306a36Sopenharmony_ci		qlcnic_write_window_reg(addr, adapter->ahw->pci_base0, data);
37462306a36Sopenharmony_ci	else
37562306a36Sopenharmony_ci		ret = qlcnic_83xx_wrt_reg_indirect(adapter, addr, data);
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	return ret;
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_cistatic int
38162306a36Sopenharmony_ciqlcnic_send_cmd_descs(struct qlcnic_adapter *adapter,
38262306a36Sopenharmony_ci		struct cmd_desc_type0 *cmd_desc_arr, int nr_desc)
38362306a36Sopenharmony_ci{
38462306a36Sopenharmony_ci	u32 i, producer;
38562306a36Sopenharmony_ci	struct qlcnic_cmd_buffer *pbuf;
38662306a36Sopenharmony_ci	struct cmd_desc_type0 *cmd_desc;
38762306a36Sopenharmony_ci	struct qlcnic_host_tx_ring *tx_ring;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	i = 0;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))
39262306a36Sopenharmony_ci		return -EIO;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	tx_ring = &adapter->tx_ring[0];
39562306a36Sopenharmony_ci	__netif_tx_lock_bh(tx_ring->txq);
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	producer = tx_ring->producer;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	if (nr_desc >= qlcnic_tx_avail(tx_ring)) {
40062306a36Sopenharmony_ci		netif_tx_stop_queue(tx_ring->txq);
40162306a36Sopenharmony_ci		smp_mb();
40262306a36Sopenharmony_ci		if (qlcnic_tx_avail(tx_ring) > nr_desc) {
40362306a36Sopenharmony_ci			if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH)
40462306a36Sopenharmony_ci				netif_tx_wake_queue(tx_ring->txq);
40562306a36Sopenharmony_ci		} else {
40662306a36Sopenharmony_ci			adapter->stats.xmit_off++;
40762306a36Sopenharmony_ci			__netif_tx_unlock_bh(tx_ring->txq);
40862306a36Sopenharmony_ci			return -EBUSY;
40962306a36Sopenharmony_ci		}
41062306a36Sopenharmony_ci	}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	do {
41362306a36Sopenharmony_ci		cmd_desc = &cmd_desc_arr[i];
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci		pbuf = &tx_ring->cmd_buf_arr[producer];
41662306a36Sopenharmony_ci		pbuf->skb = NULL;
41762306a36Sopenharmony_ci		pbuf->frag_count = 0;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci		memcpy(&tx_ring->desc_head[producer],
42062306a36Sopenharmony_ci		       cmd_desc, sizeof(struct cmd_desc_type0));
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci		producer = get_next_index(producer, tx_ring->num_desc);
42362306a36Sopenharmony_ci		i++;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	} while (i != nr_desc);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	tx_ring->producer = producer;
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	qlcnic_update_cmd_producer(tx_ring);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	__netif_tx_unlock_bh(tx_ring->txq);
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	return 0;
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ciint qlcnic_82xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,
43762306a36Sopenharmony_ci				   u16 vlan_id, u8 op)
43862306a36Sopenharmony_ci{
43962306a36Sopenharmony_ci	struct qlcnic_nic_req req;
44062306a36Sopenharmony_ci	struct qlcnic_mac_req *mac_req;
44162306a36Sopenharmony_ci	struct qlcnic_vlan_req *vlan_req;
44262306a36Sopenharmony_ci	u64 word;
44362306a36Sopenharmony_ci
44462306a36Sopenharmony_ci	memset(&req, 0, sizeof(struct qlcnic_nic_req));
44562306a36Sopenharmony_ci	req.qhdr = cpu_to_le64(QLCNIC_REQUEST << 23);
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	word = QLCNIC_MAC_EVENT | ((u64)adapter->portnum << 16);
44862306a36Sopenharmony_ci	req.req_hdr = cpu_to_le64(word);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	mac_req = (struct qlcnic_mac_req *)&req.words[0];
45162306a36Sopenharmony_ci	mac_req->op = op;
45262306a36Sopenharmony_ci	memcpy(mac_req->mac_addr, addr, ETH_ALEN);
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	vlan_req = (struct qlcnic_vlan_req *)&req.words[1];
45562306a36Sopenharmony_ci	vlan_req->vlan_id = cpu_to_le16(vlan_id);
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	return qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
45862306a36Sopenharmony_ci}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ciint qlcnic_nic_del_mac(struct qlcnic_adapter *adapter, const u8 *addr)
46162306a36Sopenharmony_ci{
46262306a36Sopenharmony_ci	struct qlcnic_mac_vlan_list *cur;
46362306a36Sopenharmony_ci	int err = -EINVAL;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	/* Delete MAC from the existing list */
46662306a36Sopenharmony_ci	list_for_each_entry(cur, &adapter->mac_list, list) {
46762306a36Sopenharmony_ci		if (ether_addr_equal(addr, cur->mac_addr)) {
46862306a36Sopenharmony_ci			err = qlcnic_sre_macaddr_change(adapter, cur->mac_addr,
46962306a36Sopenharmony_ci							0, QLCNIC_MAC_DEL);
47062306a36Sopenharmony_ci			if (err)
47162306a36Sopenharmony_ci				return err;
47262306a36Sopenharmony_ci			list_del(&cur->list);
47362306a36Sopenharmony_ci			kfree(cur);
47462306a36Sopenharmony_ci			return err;
47562306a36Sopenharmony_ci		}
47662306a36Sopenharmony_ci	}
47762306a36Sopenharmony_ci	return err;
47862306a36Sopenharmony_ci}
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ciint qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr, u16 vlan,
48162306a36Sopenharmony_ci		       enum qlcnic_mac_type mac_type)
48262306a36Sopenharmony_ci{
48362306a36Sopenharmony_ci	struct qlcnic_mac_vlan_list *cur;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	/* look up if already exists */
48662306a36Sopenharmony_ci	list_for_each_entry(cur, &adapter->mac_list, list) {
48762306a36Sopenharmony_ci		if (ether_addr_equal(addr, cur->mac_addr) &&
48862306a36Sopenharmony_ci		    cur->vlan_id == vlan)
48962306a36Sopenharmony_ci			return 0;
49062306a36Sopenharmony_ci	}
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	cur = kzalloc(sizeof(*cur), GFP_ATOMIC);
49362306a36Sopenharmony_ci	if (cur == NULL)
49462306a36Sopenharmony_ci		return -ENOMEM;
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	memcpy(cur->mac_addr, addr, ETH_ALEN);
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	if (qlcnic_sre_macaddr_change(adapter,
49962306a36Sopenharmony_ci				cur->mac_addr, vlan, QLCNIC_MAC_ADD)) {
50062306a36Sopenharmony_ci		kfree(cur);
50162306a36Sopenharmony_ci		return -EIO;
50262306a36Sopenharmony_ci	}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	cur->vlan_id = vlan;
50562306a36Sopenharmony_ci	cur->mac_type = mac_type;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	list_add_tail(&cur->list, &adapter->mac_list);
50862306a36Sopenharmony_ci	return 0;
50962306a36Sopenharmony_ci}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_civoid qlcnic_flush_mcast_mac(struct qlcnic_adapter *adapter)
51262306a36Sopenharmony_ci{
51362306a36Sopenharmony_ci	struct qlcnic_mac_vlan_list *cur;
51462306a36Sopenharmony_ci	struct list_head *head, *tmp;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	list_for_each_safe(head, tmp, &adapter->mac_list) {
51762306a36Sopenharmony_ci		cur = list_entry(head, struct qlcnic_mac_vlan_list, list);
51862306a36Sopenharmony_ci		if (cur->mac_type != QLCNIC_MULTICAST_MAC)
51962306a36Sopenharmony_ci			continue;
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci		qlcnic_sre_macaddr_change(adapter, cur->mac_addr,
52262306a36Sopenharmony_ci					  cur->vlan_id, QLCNIC_MAC_DEL);
52362306a36Sopenharmony_ci		list_del(&cur->list);
52462306a36Sopenharmony_ci		kfree(cur);
52562306a36Sopenharmony_ci	}
52662306a36Sopenharmony_ci}
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_cistatic void __qlcnic_set_multi(struct net_device *netdev, u16 vlan)
52962306a36Sopenharmony_ci{
53062306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = netdev_priv(netdev);
53162306a36Sopenharmony_ci	struct qlcnic_hardware_context *ahw = adapter->ahw;
53262306a36Sopenharmony_ci	struct netdev_hw_addr *ha;
53362306a36Sopenharmony_ci	static const u8 bcast_addr[ETH_ALEN] = {
53462306a36Sopenharmony_ci		0xff, 0xff, 0xff, 0xff, 0xff, 0xff
53562306a36Sopenharmony_ci	};
53662306a36Sopenharmony_ci	u32 mode = VPORT_MISS_MODE_DROP;
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))
53962306a36Sopenharmony_ci		return;
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	qlcnic_nic_add_mac(adapter, adapter->mac_addr, vlan,
54262306a36Sopenharmony_ci			   QLCNIC_UNICAST_MAC);
54362306a36Sopenharmony_ci	qlcnic_nic_add_mac(adapter, bcast_addr, vlan, QLCNIC_BROADCAST_MAC);
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	if (netdev->flags & IFF_PROMISC) {
54662306a36Sopenharmony_ci		if (!(adapter->flags & QLCNIC_PROMISC_DISABLED))
54762306a36Sopenharmony_ci			mode = VPORT_MISS_MODE_ACCEPT_ALL;
54862306a36Sopenharmony_ci	} else if ((netdev->flags & IFF_ALLMULTI) ||
54962306a36Sopenharmony_ci		   (netdev_mc_count(netdev) > ahw->max_mc_count)) {
55062306a36Sopenharmony_ci		mode = VPORT_MISS_MODE_ACCEPT_MULTI;
55162306a36Sopenharmony_ci	} else if (!netdev_mc_empty(netdev)) {
55262306a36Sopenharmony_ci		qlcnic_flush_mcast_mac(adapter);
55362306a36Sopenharmony_ci		netdev_for_each_mc_addr(ha, netdev)
55462306a36Sopenharmony_ci			qlcnic_nic_add_mac(adapter, ha->addr, vlan,
55562306a36Sopenharmony_ci					   QLCNIC_MULTICAST_MAC);
55662306a36Sopenharmony_ci	}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	/* configure unicast MAC address, if there is not sufficient space
55962306a36Sopenharmony_ci	 * to store all the unicast addresses then enable promiscuous mode
56062306a36Sopenharmony_ci	 */
56162306a36Sopenharmony_ci	if (netdev_uc_count(netdev) > ahw->max_uc_count) {
56262306a36Sopenharmony_ci		mode = VPORT_MISS_MODE_ACCEPT_ALL;
56362306a36Sopenharmony_ci	} else if (!netdev_uc_empty(netdev)) {
56462306a36Sopenharmony_ci		netdev_for_each_uc_addr(ha, netdev)
56562306a36Sopenharmony_ci			qlcnic_nic_add_mac(adapter, ha->addr, vlan,
56662306a36Sopenharmony_ci					   QLCNIC_UNICAST_MAC);
56762306a36Sopenharmony_ci	}
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	if (mode == VPORT_MISS_MODE_ACCEPT_ALL &&
57062306a36Sopenharmony_ci	    !adapter->fdb_mac_learn) {
57162306a36Sopenharmony_ci		qlcnic_alloc_lb_filters_mem(adapter);
57262306a36Sopenharmony_ci		adapter->drv_mac_learn = 1;
57362306a36Sopenharmony_ci		if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
57462306a36Sopenharmony_ci			adapter->rx_mac_learn = true;
57562306a36Sopenharmony_ci	} else {
57662306a36Sopenharmony_ci		adapter->drv_mac_learn = 0;
57762306a36Sopenharmony_ci		adapter->rx_mac_learn = false;
57862306a36Sopenharmony_ci	}
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	qlcnic_nic_set_promisc(adapter, mode);
58162306a36Sopenharmony_ci}
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_civoid qlcnic_set_multi(struct net_device *netdev)
58462306a36Sopenharmony_ci{
58562306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = netdev_priv(netdev);
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))
58862306a36Sopenharmony_ci		return;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	if (qlcnic_sriov_vf_check(adapter))
59162306a36Sopenharmony_ci		qlcnic_sriov_vf_set_multi(netdev);
59262306a36Sopenharmony_ci	else
59362306a36Sopenharmony_ci		__qlcnic_set_multi(netdev, 0);
59462306a36Sopenharmony_ci}
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ciint qlcnic_82xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode)
59762306a36Sopenharmony_ci{
59862306a36Sopenharmony_ci	struct qlcnic_nic_req req;
59962306a36Sopenharmony_ci	u64 word;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	memset(&req, 0, sizeof(struct qlcnic_nic_req));
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	word = QLCNIC_H2C_OPCODE_SET_MAC_RECEIVE_MODE |
60662306a36Sopenharmony_ci			((u64)adapter->portnum << 16);
60762306a36Sopenharmony_ci	req.req_hdr = cpu_to_le64(word);
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	req.words[0] = cpu_to_le64(mode);
61062306a36Sopenharmony_ci
61162306a36Sopenharmony_ci	return qlcnic_send_cmd_descs(adapter,
61262306a36Sopenharmony_ci				(struct cmd_desc_type0 *)&req, 1);
61362306a36Sopenharmony_ci}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_civoid qlcnic_82xx_free_mac_list(struct qlcnic_adapter *adapter)
61662306a36Sopenharmony_ci{
61762306a36Sopenharmony_ci	struct list_head *head = &adapter->mac_list;
61862306a36Sopenharmony_ci	struct qlcnic_mac_vlan_list *cur;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	while (!list_empty(head)) {
62162306a36Sopenharmony_ci		cur = list_entry(head->next, struct qlcnic_mac_vlan_list, list);
62262306a36Sopenharmony_ci		qlcnic_sre_macaddr_change(adapter,
62362306a36Sopenharmony_ci				cur->mac_addr, 0, QLCNIC_MAC_DEL);
62462306a36Sopenharmony_ci		list_del(&cur->list);
62562306a36Sopenharmony_ci		kfree(cur);
62662306a36Sopenharmony_ci	}
62762306a36Sopenharmony_ci}
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_civoid qlcnic_prune_lb_filters(struct qlcnic_adapter *adapter)
63062306a36Sopenharmony_ci{
63162306a36Sopenharmony_ci	struct qlcnic_filter *tmp_fil;
63262306a36Sopenharmony_ci	struct hlist_node *n;
63362306a36Sopenharmony_ci	struct hlist_head *head;
63462306a36Sopenharmony_ci	int i;
63562306a36Sopenharmony_ci	unsigned long expires;
63662306a36Sopenharmony_ci	u8 cmd;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	for (i = 0; i < adapter->fhash.fbucket_size; i++) {
63962306a36Sopenharmony_ci		head = &(adapter->fhash.fhead[i]);
64062306a36Sopenharmony_ci		hlist_for_each_entry_safe(tmp_fil, n, head, fnode) {
64162306a36Sopenharmony_ci			cmd =  tmp_fil->vlan_id ? QLCNIC_MAC_VLAN_DEL :
64262306a36Sopenharmony_ci						  QLCNIC_MAC_DEL;
64362306a36Sopenharmony_ci			expires = tmp_fil->ftime + QLCNIC_FILTER_AGE * HZ;
64462306a36Sopenharmony_ci			if (time_before(expires, jiffies)) {
64562306a36Sopenharmony_ci				qlcnic_sre_macaddr_change(adapter,
64662306a36Sopenharmony_ci							  tmp_fil->faddr,
64762306a36Sopenharmony_ci							  tmp_fil->vlan_id,
64862306a36Sopenharmony_ci							  cmd);
64962306a36Sopenharmony_ci				spin_lock_bh(&adapter->mac_learn_lock);
65062306a36Sopenharmony_ci				adapter->fhash.fnum--;
65162306a36Sopenharmony_ci				hlist_del(&tmp_fil->fnode);
65262306a36Sopenharmony_ci				spin_unlock_bh(&adapter->mac_learn_lock);
65362306a36Sopenharmony_ci				kfree(tmp_fil);
65462306a36Sopenharmony_ci			}
65562306a36Sopenharmony_ci		}
65662306a36Sopenharmony_ci	}
65762306a36Sopenharmony_ci	for (i = 0; i < adapter->rx_fhash.fbucket_size; i++) {
65862306a36Sopenharmony_ci		head = &(adapter->rx_fhash.fhead[i]);
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci		hlist_for_each_entry_safe(tmp_fil, n, head, fnode)
66162306a36Sopenharmony_ci		{
66262306a36Sopenharmony_ci			expires = tmp_fil->ftime + QLCNIC_FILTER_AGE * HZ;
66362306a36Sopenharmony_ci			if (time_before(expires, jiffies)) {
66462306a36Sopenharmony_ci				spin_lock_bh(&adapter->rx_mac_learn_lock);
66562306a36Sopenharmony_ci				adapter->rx_fhash.fnum--;
66662306a36Sopenharmony_ci				hlist_del(&tmp_fil->fnode);
66762306a36Sopenharmony_ci				spin_unlock_bh(&adapter->rx_mac_learn_lock);
66862306a36Sopenharmony_ci				kfree(tmp_fil);
66962306a36Sopenharmony_ci			}
67062306a36Sopenharmony_ci		}
67162306a36Sopenharmony_ci	}
67262306a36Sopenharmony_ci}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_civoid qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter)
67562306a36Sopenharmony_ci{
67662306a36Sopenharmony_ci	struct qlcnic_filter *tmp_fil;
67762306a36Sopenharmony_ci	struct hlist_node *n;
67862306a36Sopenharmony_ci	struct hlist_head *head;
67962306a36Sopenharmony_ci	int i;
68062306a36Sopenharmony_ci	u8 cmd;
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_ci	for (i = 0; i < adapter->fhash.fbucket_size; i++) {
68362306a36Sopenharmony_ci		head = &(adapter->fhash.fhead[i]);
68462306a36Sopenharmony_ci		hlist_for_each_entry_safe(tmp_fil, n, head, fnode) {
68562306a36Sopenharmony_ci			cmd =  tmp_fil->vlan_id ? QLCNIC_MAC_VLAN_DEL :
68662306a36Sopenharmony_ci						  QLCNIC_MAC_DEL;
68762306a36Sopenharmony_ci			qlcnic_sre_macaddr_change(adapter,
68862306a36Sopenharmony_ci						  tmp_fil->faddr,
68962306a36Sopenharmony_ci						  tmp_fil->vlan_id,
69062306a36Sopenharmony_ci						  cmd);
69162306a36Sopenharmony_ci			spin_lock_bh(&adapter->mac_learn_lock);
69262306a36Sopenharmony_ci			adapter->fhash.fnum--;
69362306a36Sopenharmony_ci			hlist_del(&tmp_fil->fnode);
69462306a36Sopenharmony_ci			spin_unlock_bh(&adapter->mac_learn_lock);
69562306a36Sopenharmony_ci			kfree(tmp_fil);
69662306a36Sopenharmony_ci		}
69762306a36Sopenharmony_ci	}
69862306a36Sopenharmony_ci}
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_cistatic int qlcnic_set_fw_loopback(struct qlcnic_adapter *adapter, u8 flag)
70162306a36Sopenharmony_ci{
70262306a36Sopenharmony_ci	struct qlcnic_nic_req req;
70362306a36Sopenharmony_ci	int rv;
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	memset(&req, 0, sizeof(struct qlcnic_nic_req));
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
70862306a36Sopenharmony_ci	req.req_hdr = cpu_to_le64(QLCNIC_H2C_OPCODE_CONFIG_LOOPBACK |
70962306a36Sopenharmony_ci		((u64) adapter->portnum << 16) | ((u64) 0x1 << 32));
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	req.words[0] = cpu_to_le64(flag);
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
71462306a36Sopenharmony_ci	if (rv != 0)
71562306a36Sopenharmony_ci		dev_err(&adapter->pdev->dev, "%sting loopback mode failed\n",
71662306a36Sopenharmony_ci				flag ? "Set" : "Reset");
71762306a36Sopenharmony_ci	return rv;
71862306a36Sopenharmony_ci}
71962306a36Sopenharmony_ci
72062306a36Sopenharmony_ciint qlcnic_82xx_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
72162306a36Sopenharmony_ci{
72262306a36Sopenharmony_ci	if (qlcnic_set_fw_loopback(adapter, mode))
72362306a36Sopenharmony_ci		return -EIO;
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	if (qlcnic_nic_set_promisc(adapter,
72662306a36Sopenharmony_ci				   VPORT_MISS_MODE_ACCEPT_ALL)) {
72762306a36Sopenharmony_ci		qlcnic_set_fw_loopback(adapter, 0);
72862306a36Sopenharmony_ci		return -EIO;
72962306a36Sopenharmony_ci	}
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	msleep(1000);
73262306a36Sopenharmony_ci	return 0;
73362306a36Sopenharmony_ci}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ciint qlcnic_82xx_clear_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
73662306a36Sopenharmony_ci{
73762306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
73862306a36Sopenharmony_ci
73962306a36Sopenharmony_ci	mode = VPORT_MISS_MODE_DROP;
74062306a36Sopenharmony_ci	qlcnic_set_fw_loopback(adapter, 0);
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci	if (netdev->flags & IFF_PROMISC)
74362306a36Sopenharmony_ci		mode = VPORT_MISS_MODE_ACCEPT_ALL;
74462306a36Sopenharmony_ci	else if (netdev->flags & IFF_ALLMULTI)
74562306a36Sopenharmony_ci		mode = VPORT_MISS_MODE_ACCEPT_MULTI;
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	qlcnic_nic_set_promisc(adapter, mode);
74862306a36Sopenharmony_ci	msleep(1000);
74962306a36Sopenharmony_ci	return 0;
75062306a36Sopenharmony_ci}
75162306a36Sopenharmony_ci
75262306a36Sopenharmony_ciint qlcnic_82xx_read_phys_port_id(struct qlcnic_adapter *adapter)
75362306a36Sopenharmony_ci{
75462306a36Sopenharmony_ci	u8 mac[ETH_ALEN];
75562306a36Sopenharmony_ci	int ret;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	ret = qlcnic_get_mac_address(adapter, mac,
75862306a36Sopenharmony_ci				     adapter->ahw->physical_port);
75962306a36Sopenharmony_ci	if (ret)
76062306a36Sopenharmony_ci		return ret;
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	memcpy(adapter->ahw->phys_port_id, mac, ETH_ALEN);
76362306a36Sopenharmony_ci	adapter->flags |= QLCNIC_HAS_PHYS_PORT_ID;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	return 0;
76662306a36Sopenharmony_ci}
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ciint qlcnic_82xx_set_rx_coalesce(struct qlcnic_adapter *adapter)
76962306a36Sopenharmony_ci{
77062306a36Sopenharmony_ci	struct qlcnic_nic_req req;
77162306a36Sopenharmony_ci	int rv;
77262306a36Sopenharmony_ci
77362306a36Sopenharmony_ci	memset(&req, 0, sizeof(struct qlcnic_nic_req));
77462306a36Sopenharmony_ci
77562306a36Sopenharmony_ci	req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	req.req_hdr = cpu_to_le64(QLCNIC_CONFIG_INTR_COALESCE |
77862306a36Sopenharmony_ci		((u64) adapter->portnum << 16));
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	req.words[0] = cpu_to_le64(((u64) adapter->ahw->coal.flag) << 32);
78162306a36Sopenharmony_ci	req.words[2] = cpu_to_le64(adapter->ahw->coal.rx_packets |
78262306a36Sopenharmony_ci			((u64) adapter->ahw->coal.rx_time_us) << 16);
78362306a36Sopenharmony_ci	req.words[5] = cpu_to_le64(adapter->ahw->coal.timer_out |
78462306a36Sopenharmony_ci			((u64) adapter->ahw->coal.type) << 32 |
78562306a36Sopenharmony_ci			((u64) adapter->ahw->coal.sts_ring_mask) << 40);
78662306a36Sopenharmony_ci	rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
78762306a36Sopenharmony_ci	if (rv != 0)
78862306a36Sopenharmony_ci		dev_err(&adapter->netdev->dev,
78962306a36Sopenharmony_ci			"Could not send interrupt coalescing parameters\n");
79062306a36Sopenharmony_ci
79162306a36Sopenharmony_ci	return rv;
79262306a36Sopenharmony_ci}
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci/* Send the interrupt coalescing parameter set by ethtool to the card. */
79562306a36Sopenharmony_ciint qlcnic_82xx_config_intr_coalesce(struct qlcnic_adapter *adapter,
79662306a36Sopenharmony_ci				     struct ethtool_coalesce *ethcoal)
79762306a36Sopenharmony_ci{
79862306a36Sopenharmony_ci	struct qlcnic_nic_intr_coalesce *coal = &adapter->ahw->coal;
79962306a36Sopenharmony_ci	int rv;
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	coal->flag = QLCNIC_INTR_DEFAULT;
80262306a36Sopenharmony_ci	coal->rx_time_us = ethcoal->rx_coalesce_usecs;
80362306a36Sopenharmony_ci	coal->rx_packets = ethcoal->rx_max_coalesced_frames;
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	rv = qlcnic_82xx_set_rx_coalesce(adapter);
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	if (rv)
80862306a36Sopenharmony_ci		netdev_err(adapter->netdev,
80962306a36Sopenharmony_ci			   "Failed to set Rx coalescing parameters\n");
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	return rv;
81262306a36Sopenharmony_ci}
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci#define QLCNIC_ENABLE_IPV4_LRO		BIT_0
81562306a36Sopenharmony_ci#define QLCNIC_ENABLE_IPV6_LRO		(BIT_1 | BIT_9)
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ciint qlcnic_82xx_config_hw_lro(struct qlcnic_adapter *adapter, int enable)
81862306a36Sopenharmony_ci{
81962306a36Sopenharmony_ci	struct qlcnic_nic_req req;
82062306a36Sopenharmony_ci	u64 word;
82162306a36Sopenharmony_ci	int rv;
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))
82462306a36Sopenharmony_ci		return 0;
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	memset(&req, 0, sizeof(struct qlcnic_nic_req));
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_ci	word = QLCNIC_H2C_OPCODE_CONFIG_HW_LRO | ((u64)adapter->portnum << 16);
83162306a36Sopenharmony_ci	req.req_hdr = cpu_to_le64(word);
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	word = 0;
83462306a36Sopenharmony_ci	if (enable) {
83562306a36Sopenharmony_ci		word = QLCNIC_ENABLE_IPV4_LRO;
83662306a36Sopenharmony_ci		if (adapter->ahw->extra_capability[0] &
83762306a36Sopenharmony_ci		    QLCNIC_FW_CAP2_HW_LRO_IPV6)
83862306a36Sopenharmony_ci			word |= QLCNIC_ENABLE_IPV6_LRO;
83962306a36Sopenharmony_ci	}
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_ci	req.words[0] = cpu_to_le64(word);
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
84462306a36Sopenharmony_ci	if (rv != 0)
84562306a36Sopenharmony_ci		dev_err(&adapter->netdev->dev,
84662306a36Sopenharmony_ci			"Could not send configure hw lro request\n");
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	return rv;
84962306a36Sopenharmony_ci}
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ciint qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable)
85262306a36Sopenharmony_ci{
85362306a36Sopenharmony_ci	struct qlcnic_nic_req req;
85462306a36Sopenharmony_ci	u64 word;
85562306a36Sopenharmony_ci	int rv;
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_ci	if (!!(adapter->flags & QLCNIC_BRIDGE_ENABLED) == enable)
85862306a36Sopenharmony_ci		return 0;
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	memset(&req, 0, sizeof(struct qlcnic_nic_req));
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_ci	word = QLCNIC_H2C_OPCODE_CONFIG_BRIDGING |
86562306a36Sopenharmony_ci		((u64)adapter->portnum << 16);
86662306a36Sopenharmony_ci	req.req_hdr = cpu_to_le64(word);
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	req.words[0] = cpu_to_le64(enable);
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
87162306a36Sopenharmony_ci	if (rv != 0)
87262306a36Sopenharmony_ci		dev_err(&adapter->netdev->dev,
87362306a36Sopenharmony_ci			"Could not send configure bridge mode request\n");
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	adapter->flags ^= QLCNIC_BRIDGE_ENABLED;
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	return rv;
87862306a36Sopenharmony_ci}
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci#define QLCNIC_RSS_HASHTYPE_IP_TCP	0x3
88262306a36Sopenharmony_ci#define QLCNIC_ENABLE_TYPE_C_RSS	BIT_10
88362306a36Sopenharmony_ci#define QLCNIC_RSS_FEATURE_FLAG	(1ULL << 63)
88462306a36Sopenharmony_ci#define QLCNIC_RSS_IND_TABLE_MASK	0x7ULL
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ciint qlcnic_82xx_config_rss(struct qlcnic_adapter *adapter, int enable)
88762306a36Sopenharmony_ci{
88862306a36Sopenharmony_ci	struct qlcnic_nic_req req;
88962306a36Sopenharmony_ci	u64 word;
89062306a36Sopenharmony_ci	int i, rv;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	static const u64 key[] = {
89362306a36Sopenharmony_ci		0xbeac01fa6a42b73bULL, 0x8030f20c77cb2da3ULL,
89462306a36Sopenharmony_ci		0xae7b30b4d0ca2bcbULL, 0x43a38fb04167253dULL,
89562306a36Sopenharmony_ci		0x255b0ec26d5a56daULL
89662306a36Sopenharmony_ci	};
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	memset(&req, 0, sizeof(struct qlcnic_nic_req));
89962306a36Sopenharmony_ci	req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	word = QLCNIC_H2C_OPCODE_CONFIG_RSS | ((u64)adapter->portnum << 16);
90262306a36Sopenharmony_ci	req.req_hdr = cpu_to_le64(word);
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	/*
90562306a36Sopenharmony_ci	 * RSS request:
90662306a36Sopenharmony_ci	 * bits 3-0: hash_method
90762306a36Sopenharmony_ci	 *      5-4: hash_type_ipv4
90862306a36Sopenharmony_ci	 *	7-6: hash_type_ipv6
90962306a36Sopenharmony_ci	 *	  8: enable
91062306a36Sopenharmony_ci	 *        9: use indirection table
91162306a36Sopenharmony_ci	 *       10: type-c rss
91262306a36Sopenharmony_ci	 *	 11: udp rss
91362306a36Sopenharmony_ci	 *    47-12: reserved
91462306a36Sopenharmony_ci	 *    62-48: indirection table mask
91562306a36Sopenharmony_ci	 *	 63: feature flag
91662306a36Sopenharmony_ci	 */
91762306a36Sopenharmony_ci	word =  ((u64)(QLCNIC_RSS_HASHTYPE_IP_TCP & 0x3) << 4) |
91862306a36Sopenharmony_ci		((u64)(QLCNIC_RSS_HASHTYPE_IP_TCP & 0x3) << 6) |
91962306a36Sopenharmony_ci		((u64)(enable & 0x1) << 8) |
92062306a36Sopenharmony_ci		((u64)QLCNIC_RSS_IND_TABLE_MASK << 48) |
92162306a36Sopenharmony_ci		(u64)QLCNIC_ENABLE_TYPE_C_RSS |
92262306a36Sopenharmony_ci		(u64)QLCNIC_RSS_FEATURE_FLAG;
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	req.words[0] = cpu_to_le64(word);
92562306a36Sopenharmony_ci	for (i = 0; i < 5; i++)
92662306a36Sopenharmony_ci		req.words[i+1] = cpu_to_le64(key[i]);
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
92962306a36Sopenharmony_ci	if (rv != 0)
93062306a36Sopenharmony_ci		dev_err(&adapter->netdev->dev, "could not configure RSS\n");
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_ci	return rv;
93362306a36Sopenharmony_ci}
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_civoid qlcnic_82xx_config_ipaddr(struct qlcnic_adapter *adapter,
93662306a36Sopenharmony_ci			       __be32 ip, int cmd)
93762306a36Sopenharmony_ci{
93862306a36Sopenharmony_ci	struct qlcnic_nic_req req;
93962306a36Sopenharmony_ci	struct qlcnic_ipaddr *ipa;
94062306a36Sopenharmony_ci	u64 word;
94162306a36Sopenharmony_ci	int rv;
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	memset(&req, 0, sizeof(struct qlcnic_nic_req));
94462306a36Sopenharmony_ci	req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	word = QLCNIC_H2C_OPCODE_CONFIG_IPADDR | ((u64)adapter->portnum << 16);
94762306a36Sopenharmony_ci	req.req_hdr = cpu_to_le64(word);
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	req.words[0] = cpu_to_le64(cmd);
95062306a36Sopenharmony_ci	ipa = (struct qlcnic_ipaddr *)&req.words[1];
95162306a36Sopenharmony_ci	ipa->ipv4 = ip;
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
95462306a36Sopenharmony_ci	if (rv != 0)
95562306a36Sopenharmony_ci		dev_err(&adapter->netdev->dev,
95662306a36Sopenharmony_ci				"could not notify %s IP 0x%x request\n",
95762306a36Sopenharmony_ci				(cmd == QLCNIC_IP_UP) ? "Add" : "Remove", ip);
95862306a36Sopenharmony_ci}
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ciint qlcnic_82xx_linkevent_request(struct qlcnic_adapter *adapter, int enable)
96162306a36Sopenharmony_ci{
96262306a36Sopenharmony_ci	struct qlcnic_nic_req req;
96362306a36Sopenharmony_ci	u64 word;
96462306a36Sopenharmony_ci	int rv;
96562306a36Sopenharmony_ci	memset(&req, 0, sizeof(struct qlcnic_nic_req));
96662306a36Sopenharmony_ci	req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	word = QLCNIC_H2C_OPCODE_GET_LINKEVENT | ((u64)adapter->portnum << 16);
96962306a36Sopenharmony_ci	req.req_hdr = cpu_to_le64(word);
97062306a36Sopenharmony_ci	req.words[0] = cpu_to_le64(enable | (enable << 8));
97162306a36Sopenharmony_ci	rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
97262306a36Sopenharmony_ci	if (rv != 0)
97362306a36Sopenharmony_ci		dev_err(&adapter->netdev->dev,
97462306a36Sopenharmony_ci				"could not configure link notification\n");
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	return rv;
97762306a36Sopenharmony_ci}
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_cistatic int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter)
98062306a36Sopenharmony_ci{
98162306a36Sopenharmony_ci	struct qlcnic_nic_req req;
98262306a36Sopenharmony_ci	u64 word;
98362306a36Sopenharmony_ci	int rv;
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))
98662306a36Sopenharmony_ci		return 0;
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	memset(&req, 0, sizeof(struct qlcnic_nic_req));
98962306a36Sopenharmony_ci	req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	word = QLCNIC_H2C_OPCODE_LRO_REQUEST |
99262306a36Sopenharmony_ci		((u64)adapter->portnum << 16) |
99362306a36Sopenharmony_ci		((u64)QLCNIC_LRO_REQUEST_CLEANUP << 56) ;
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	req.req_hdr = cpu_to_le64(word);
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
99862306a36Sopenharmony_ci	if (rv != 0)
99962306a36Sopenharmony_ci		dev_err(&adapter->netdev->dev,
100062306a36Sopenharmony_ci				 "could not cleanup lro flows\n");
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	return rv;
100362306a36Sopenharmony_ci}
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci/*
100662306a36Sopenharmony_ci * qlcnic_change_mtu - Change the Maximum Transfer Unit
100762306a36Sopenharmony_ci * @returns 0 on success, negative on failure
100862306a36Sopenharmony_ci */
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ciint qlcnic_change_mtu(struct net_device *netdev, int mtu)
101162306a36Sopenharmony_ci{
101262306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = netdev_priv(netdev);
101362306a36Sopenharmony_ci	int rc = 0;
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	rc = qlcnic_fw_cmd_set_mtu(adapter, mtu);
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	if (!rc)
101862306a36Sopenharmony_ci		netdev->mtu = mtu;
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	return rc;
102162306a36Sopenharmony_ci}
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_cistatic netdev_features_t qlcnic_process_flags(struct qlcnic_adapter *adapter,
102462306a36Sopenharmony_ci					      netdev_features_t features)
102562306a36Sopenharmony_ci{
102662306a36Sopenharmony_ci	u32 offload_flags = adapter->offload_flags;
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	if (offload_flags & BIT_0) {
102962306a36Sopenharmony_ci		features |= NETIF_F_RXCSUM | NETIF_F_IP_CSUM |
103062306a36Sopenharmony_ci			    NETIF_F_IPV6_CSUM;
103162306a36Sopenharmony_ci		adapter->rx_csum = 1;
103262306a36Sopenharmony_ci		if (QLCNIC_IS_TSO_CAPABLE(adapter)) {
103362306a36Sopenharmony_ci			if (!(offload_flags & BIT_1))
103462306a36Sopenharmony_ci				features &= ~NETIF_F_TSO;
103562306a36Sopenharmony_ci			else
103662306a36Sopenharmony_ci				features |= NETIF_F_TSO;
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci			if (!(offload_flags & BIT_2))
103962306a36Sopenharmony_ci				features &= ~NETIF_F_TSO6;
104062306a36Sopenharmony_ci			else
104162306a36Sopenharmony_ci				features |= NETIF_F_TSO6;
104262306a36Sopenharmony_ci		}
104362306a36Sopenharmony_ci	} else {
104462306a36Sopenharmony_ci		features &= ~(NETIF_F_RXCSUM |
104562306a36Sopenharmony_ci			      NETIF_F_IP_CSUM |
104662306a36Sopenharmony_ci			      NETIF_F_IPV6_CSUM);
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci		if (QLCNIC_IS_TSO_CAPABLE(adapter))
104962306a36Sopenharmony_ci			features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
105062306a36Sopenharmony_ci		adapter->rx_csum = 0;
105162306a36Sopenharmony_ci	}
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	return features;
105462306a36Sopenharmony_ci}
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_cinetdev_features_t qlcnic_fix_features(struct net_device *netdev,
105762306a36Sopenharmony_ci	netdev_features_t features)
105862306a36Sopenharmony_ci{
105962306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = netdev_priv(netdev);
106062306a36Sopenharmony_ci	netdev_features_t changed;
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	if (qlcnic_82xx_check(adapter) &&
106362306a36Sopenharmony_ci	    (adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
106462306a36Sopenharmony_ci		if (adapter->flags & QLCNIC_APP_CHANGED_FLAGS) {
106562306a36Sopenharmony_ci			features = qlcnic_process_flags(adapter, features);
106662306a36Sopenharmony_ci		} else {
106762306a36Sopenharmony_ci			changed = features ^ netdev->features;
106862306a36Sopenharmony_ci			features ^= changed & (NETIF_F_RXCSUM |
106962306a36Sopenharmony_ci					       NETIF_F_IP_CSUM |
107062306a36Sopenharmony_ci					       NETIF_F_IPV6_CSUM |
107162306a36Sopenharmony_ci					       NETIF_F_TSO |
107262306a36Sopenharmony_ci					       NETIF_F_TSO6);
107362306a36Sopenharmony_ci		}
107462306a36Sopenharmony_ci	}
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	if (!(features & NETIF_F_RXCSUM))
107762306a36Sopenharmony_ci		features &= ~NETIF_F_LRO;
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	return features;
108062306a36Sopenharmony_ci}
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ciint qlcnic_set_features(struct net_device *netdev, netdev_features_t features)
108462306a36Sopenharmony_ci{
108562306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = netdev_priv(netdev);
108662306a36Sopenharmony_ci	netdev_features_t changed = netdev->features ^ features;
108762306a36Sopenharmony_ci	int hw_lro = (features & NETIF_F_LRO) ? QLCNIC_LRO_ENABLED : 0;
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	if (!(changed & NETIF_F_LRO))
109062306a36Sopenharmony_ci		return 0;
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	netdev->features ^= NETIF_F_LRO;
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	if (qlcnic_config_hw_lro(adapter, hw_lro))
109562306a36Sopenharmony_ci		return -EIO;
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	if (!hw_lro && qlcnic_82xx_check(adapter)) {
109862306a36Sopenharmony_ci		if (qlcnic_send_lro_cleanup(adapter))
109962306a36Sopenharmony_ci			return -EIO;
110062306a36Sopenharmony_ci	}
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci	return 0;
110362306a36Sopenharmony_ci}
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci/*
110662306a36Sopenharmony_ci * Changes the CRB window to the specified window.
110762306a36Sopenharmony_ci */
110862306a36Sopenharmony_ci /* Returns < 0 if off is not valid,
110962306a36Sopenharmony_ci *	 1 if window access is needed. 'off' is set to offset from
111062306a36Sopenharmony_ci *	   CRB space in 128M pci map
111162306a36Sopenharmony_ci *	 0 if no window access is needed. 'off' is set to 2M addr
111262306a36Sopenharmony_ci * In: 'off' is offset from base in 128M pci map
111362306a36Sopenharmony_ci */
111462306a36Sopenharmony_cistatic int qlcnic_pci_get_crb_addr_2M(struct qlcnic_hardware_context *ahw,
111562306a36Sopenharmony_ci				      ulong off, void __iomem **addr)
111662306a36Sopenharmony_ci{
111762306a36Sopenharmony_ci	const struct crb_128M_2M_sub_block_map *m;
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_ci	if ((off >= QLCNIC_CRB_MAX) || (off < QLCNIC_PCI_CRBSPACE))
112062306a36Sopenharmony_ci		return -EINVAL;
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	off -= QLCNIC_PCI_CRBSPACE;
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	/*
112562306a36Sopenharmony_ci	 * Try direct map
112662306a36Sopenharmony_ci	 */
112762306a36Sopenharmony_ci	m = &crb_128M_2M_map[CRB_BLK(off)].sub_block[CRB_SUBBLK(off)];
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	if (m->valid && (m->start_128M <= off) && (m->end_128M > off)) {
113062306a36Sopenharmony_ci		*addr = ahw->pci_base0 + m->start_2M +
113162306a36Sopenharmony_ci			(off - m->start_128M);
113262306a36Sopenharmony_ci		return 0;
113362306a36Sopenharmony_ci	}
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci	/*
113662306a36Sopenharmony_ci	 * Not in direct map, use crb window
113762306a36Sopenharmony_ci	 */
113862306a36Sopenharmony_ci	*addr = ahw->pci_base0 + CRB_INDIRECT_2M + (off & MASK(16));
113962306a36Sopenharmony_ci	return 1;
114062306a36Sopenharmony_ci}
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci/*
114362306a36Sopenharmony_ci * In: 'off' is offset from CRB space in 128M pci map
114462306a36Sopenharmony_ci * Out: 'off' is 2M pci map addr
114562306a36Sopenharmony_ci * side effect: lock crb window
114662306a36Sopenharmony_ci */
114762306a36Sopenharmony_cistatic int
114862306a36Sopenharmony_ciqlcnic_pci_set_crbwindow_2M(struct qlcnic_adapter *adapter, ulong off)
114962306a36Sopenharmony_ci{
115062306a36Sopenharmony_ci	u32 window;
115162306a36Sopenharmony_ci	void __iomem *addr = adapter->ahw->pci_base0 + CRB_WINDOW_2M;
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci	off -= QLCNIC_PCI_CRBSPACE;
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci	window = CRB_HI(off);
115662306a36Sopenharmony_ci	if (window == 0) {
115762306a36Sopenharmony_ci		dev_err(&adapter->pdev->dev, "Invalid offset 0x%lx\n", off);
115862306a36Sopenharmony_ci		return -EIO;
115962306a36Sopenharmony_ci	}
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	writel(window, addr);
116262306a36Sopenharmony_ci	if (readl(addr) != window) {
116362306a36Sopenharmony_ci		if (printk_ratelimit())
116462306a36Sopenharmony_ci			dev_warn(&adapter->pdev->dev,
116562306a36Sopenharmony_ci				"failed to set CRB window to %d off 0x%lx\n",
116662306a36Sopenharmony_ci				window, off);
116762306a36Sopenharmony_ci		return -EIO;
116862306a36Sopenharmony_ci	}
116962306a36Sopenharmony_ci	return 0;
117062306a36Sopenharmony_ci}
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ciint qlcnic_82xx_hw_write_wx_2M(struct qlcnic_adapter *adapter, ulong off,
117362306a36Sopenharmony_ci			       u32 data)
117462306a36Sopenharmony_ci{
117562306a36Sopenharmony_ci	unsigned long flags;
117662306a36Sopenharmony_ci	int rv;
117762306a36Sopenharmony_ci	void __iomem *addr = NULL;
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	rv = qlcnic_pci_get_crb_addr_2M(adapter->ahw, off, &addr);
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci	if (rv == 0) {
118262306a36Sopenharmony_ci		writel(data, addr);
118362306a36Sopenharmony_ci		return 0;
118462306a36Sopenharmony_ci	}
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	if (rv > 0) {
118762306a36Sopenharmony_ci		/* indirect access */
118862306a36Sopenharmony_ci		write_lock_irqsave(&adapter->ahw->crb_lock, flags);
118962306a36Sopenharmony_ci		crb_win_lock(adapter);
119062306a36Sopenharmony_ci		rv = qlcnic_pci_set_crbwindow_2M(adapter, off);
119162306a36Sopenharmony_ci		if (!rv)
119262306a36Sopenharmony_ci			writel(data, addr);
119362306a36Sopenharmony_ci		crb_win_unlock(adapter);
119462306a36Sopenharmony_ci		write_unlock_irqrestore(&adapter->ahw->crb_lock, flags);
119562306a36Sopenharmony_ci		return rv;
119662306a36Sopenharmony_ci	}
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci	dev_err(&adapter->pdev->dev,
119962306a36Sopenharmony_ci			"%s: invalid offset: 0x%016lx\n", __func__, off);
120062306a36Sopenharmony_ci	dump_stack();
120162306a36Sopenharmony_ci	return -EIO;
120262306a36Sopenharmony_ci}
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ciint qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off,
120562306a36Sopenharmony_ci			      int *err)
120662306a36Sopenharmony_ci{
120762306a36Sopenharmony_ci	unsigned long flags;
120862306a36Sopenharmony_ci	int rv;
120962306a36Sopenharmony_ci	u32 data = -1;
121062306a36Sopenharmony_ci	void __iomem *addr = NULL;
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	rv = qlcnic_pci_get_crb_addr_2M(adapter->ahw, off, &addr);
121362306a36Sopenharmony_ci
121462306a36Sopenharmony_ci	if (rv == 0)
121562306a36Sopenharmony_ci		return readl(addr);
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci	if (rv > 0) {
121862306a36Sopenharmony_ci		/* indirect access */
121962306a36Sopenharmony_ci		write_lock_irqsave(&adapter->ahw->crb_lock, flags);
122062306a36Sopenharmony_ci		crb_win_lock(adapter);
122162306a36Sopenharmony_ci		if (!qlcnic_pci_set_crbwindow_2M(adapter, off))
122262306a36Sopenharmony_ci			data = readl(addr);
122362306a36Sopenharmony_ci		crb_win_unlock(adapter);
122462306a36Sopenharmony_ci		write_unlock_irqrestore(&adapter->ahw->crb_lock, flags);
122562306a36Sopenharmony_ci		return data;
122662306a36Sopenharmony_ci	}
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci	dev_err(&adapter->pdev->dev,
122962306a36Sopenharmony_ci			"%s: invalid offset: 0x%016lx\n", __func__, off);
123062306a36Sopenharmony_ci	dump_stack();
123162306a36Sopenharmony_ci	return -1;
123262306a36Sopenharmony_ci}
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_civoid __iomem *qlcnic_get_ioaddr(struct qlcnic_hardware_context *ahw,
123562306a36Sopenharmony_ci				u32 offset)
123662306a36Sopenharmony_ci{
123762306a36Sopenharmony_ci	void __iomem *addr = NULL;
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci	WARN_ON(qlcnic_pci_get_crb_addr_2M(ahw, offset, &addr));
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	return addr;
124262306a36Sopenharmony_ci}
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_cistatic int qlcnic_pci_mem_access_direct(struct qlcnic_adapter *adapter,
124562306a36Sopenharmony_ci					u32 window, u64 off, u64 *data, int op)
124662306a36Sopenharmony_ci{
124762306a36Sopenharmony_ci	void __iomem *addr;
124862306a36Sopenharmony_ci	u32 start;
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	mutex_lock(&adapter->ahw->mem_lock);
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	writel(window, adapter->ahw->ocm_win_crb);
125362306a36Sopenharmony_ci	/* read back to flush */
125462306a36Sopenharmony_ci	readl(adapter->ahw->ocm_win_crb);
125562306a36Sopenharmony_ci	start = QLCNIC_PCI_OCM0_2M + off;
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	addr = adapter->ahw->pci_base0 + start;
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	if (op == 0)	/* read */
126062306a36Sopenharmony_ci		*data = readq(addr);
126162306a36Sopenharmony_ci	else		/* write */
126262306a36Sopenharmony_ci		writeq(*data, addr);
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci	/* Set window to 0 */
126562306a36Sopenharmony_ci	writel(0, adapter->ahw->ocm_win_crb);
126662306a36Sopenharmony_ci	readl(adapter->ahw->ocm_win_crb);
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	mutex_unlock(&adapter->ahw->mem_lock);
126962306a36Sopenharmony_ci	return 0;
127062306a36Sopenharmony_ci}
127162306a36Sopenharmony_ci
127262306a36Sopenharmony_cistatic void
127362306a36Sopenharmony_ciqlcnic_pci_camqm_read_2M(struct qlcnic_adapter *adapter, u64 off, u64 *data)
127462306a36Sopenharmony_ci{
127562306a36Sopenharmony_ci	void __iomem *addr = adapter->ahw->pci_base0 +
127662306a36Sopenharmony_ci		QLCNIC_PCI_CAMQM_2M_BASE + (off - QLCNIC_PCI_CAMQM);
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	mutex_lock(&adapter->ahw->mem_lock);
127962306a36Sopenharmony_ci	*data = readq(addr);
128062306a36Sopenharmony_ci	mutex_unlock(&adapter->ahw->mem_lock);
128162306a36Sopenharmony_ci}
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_cistatic void
128462306a36Sopenharmony_ciqlcnic_pci_camqm_write_2M(struct qlcnic_adapter *adapter, u64 off, u64 data)
128562306a36Sopenharmony_ci{
128662306a36Sopenharmony_ci	void __iomem *addr = adapter->ahw->pci_base0 +
128762306a36Sopenharmony_ci		QLCNIC_PCI_CAMQM_2M_BASE + (off - QLCNIC_PCI_CAMQM);
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	mutex_lock(&adapter->ahw->mem_lock);
129062306a36Sopenharmony_ci	writeq(data, addr);
129162306a36Sopenharmony_ci	mutex_unlock(&adapter->ahw->mem_lock);
129262306a36Sopenharmony_ci}
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci/* Set MS memory control data for different adapters */
129762306a36Sopenharmony_cistatic void qlcnic_set_ms_controls(struct qlcnic_adapter *adapter, u64 off,
129862306a36Sopenharmony_ci				   struct qlcnic_ms_reg_ctrl *ms)
129962306a36Sopenharmony_ci{
130062306a36Sopenharmony_ci	ms->control = QLCNIC_MS_CTRL;
130162306a36Sopenharmony_ci	ms->low = QLCNIC_MS_ADDR_LO;
130262306a36Sopenharmony_ci	ms->hi = QLCNIC_MS_ADDR_HI;
130362306a36Sopenharmony_ci	if (off & 0xf) {
130462306a36Sopenharmony_ci		ms->wd[0] = QLCNIC_MS_WRTDATA_LO;
130562306a36Sopenharmony_ci		ms->rd[0] = QLCNIC_MS_RDDATA_LO;
130662306a36Sopenharmony_ci		ms->wd[1] = QLCNIC_MS_WRTDATA_HI;
130762306a36Sopenharmony_ci		ms->rd[1] = QLCNIC_MS_RDDATA_HI;
130862306a36Sopenharmony_ci		ms->wd[2] = QLCNIC_MS_WRTDATA_ULO;
130962306a36Sopenharmony_ci		ms->wd[3] = QLCNIC_MS_WRTDATA_UHI;
131062306a36Sopenharmony_ci		ms->rd[2] = QLCNIC_MS_RDDATA_ULO;
131162306a36Sopenharmony_ci		ms->rd[3] = QLCNIC_MS_RDDATA_UHI;
131262306a36Sopenharmony_ci	} else {
131362306a36Sopenharmony_ci		ms->wd[0] = QLCNIC_MS_WRTDATA_ULO;
131462306a36Sopenharmony_ci		ms->rd[0] = QLCNIC_MS_RDDATA_ULO;
131562306a36Sopenharmony_ci		ms->wd[1] = QLCNIC_MS_WRTDATA_UHI;
131662306a36Sopenharmony_ci		ms->rd[1] = QLCNIC_MS_RDDATA_UHI;
131762306a36Sopenharmony_ci		ms->wd[2] = QLCNIC_MS_WRTDATA_LO;
131862306a36Sopenharmony_ci		ms->wd[3] = QLCNIC_MS_WRTDATA_HI;
131962306a36Sopenharmony_ci		ms->rd[2] = QLCNIC_MS_RDDATA_LO;
132062306a36Sopenharmony_ci		ms->rd[3] = QLCNIC_MS_RDDATA_HI;
132162306a36Sopenharmony_ci	}
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci	ms->ocm_window = OCM_WIN_P3P(off);
132462306a36Sopenharmony_ci	ms->off = GET_MEM_OFFS_2M(off);
132562306a36Sopenharmony_ci}
132662306a36Sopenharmony_ci
132762306a36Sopenharmony_ciint qlcnic_pci_mem_write_2M(struct qlcnic_adapter *adapter, u64 off, u64 data)
132862306a36Sopenharmony_ci{
132962306a36Sopenharmony_ci	int j, ret = 0;
133062306a36Sopenharmony_ci	u32 temp, off8;
133162306a36Sopenharmony_ci	struct qlcnic_ms_reg_ctrl ms;
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	/* Only 64-bit aligned access */
133462306a36Sopenharmony_ci	if (off & 7)
133562306a36Sopenharmony_ci		return -EIO;
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_ci	memset(&ms, 0, sizeof(struct qlcnic_ms_reg_ctrl));
133862306a36Sopenharmony_ci	if (!(ADDR_IN_RANGE(off, QLCNIC_ADDR_QDR_NET,
133962306a36Sopenharmony_ci			    QLCNIC_ADDR_QDR_NET_MAX) ||
134062306a36Sopenharmony_ci	      ADDR_IN_RANGE(off, QLCNIC_ADDR_DDR_NET,
134162306a36Sopenharmony_ci			    QLCNIC_ADDR_DDR_NET_MAX)))
134262306a36Sopenharmony_ci		return -EIO;
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci	qlcnic_set_ms_controls(adapter, off, &ms);
134562306a36Sopenharmony_ci
134662306a36Sopenharmony_ci	if (ADDR_IN_RANGE(off, QLCNIC_ADDR_OCM0, QLCNIC_ADDR_OCM0_MAX))
134762306a36Sopenharmony_ci		return qlcnic_pci_mem_access_direct(adapter, ms.ocm_window,
134862306a36Sopenharmony_ci						    ms.off, &data, 1);
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_ci	off8 = off & ~0xf;
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	mutex_lock(&adapter->ahw->mem_lock);
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci	qlcnic_ind_wr(adapter, ms.low, off8);
135562306a36Sopenharmony_ci	qlcnic_ind_wr(adapter, ms.hi, 0);
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	qlcnic_ind_wr(adapter, ms.control, TA_CTL_ENABLE);
135862306a36Sopenharmony_ci	qlcnic_ind_wr(adapter, ms.control, QLCNIC_TA_START_ENABLE);
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	for (j = 0; j < MAX_CTL_CHECK; j++) {
136162306a36Sopenharmony_ci		temp = qlcnic_ind_rd(adapter, ms.control);
136262306a36Sopenharmony_ci		if ((temp & TA_CTL_BUSY) == 0)
136362306a36Sopenharmony_ci			break;
136462306a36Sopenharmony_ci	}
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci	if (j >= MAX_CTL_CHECK) {
136762306a36Sopenharmony_ci		ret = -EIO;
136862306a36Sopenharmony_ci		goto done;
136962306a36Sopenharmony_ci	}
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_ci	/* This is the modify part of read-modify-write */
137262306a36Sopenharmony_ci	qlcnic_ind_wr(adapter, ms.wd[0], qlcnic_ind_rd(adapter, ms.rd[0]));
137362306a36Sopenharmony_ci	qlcnic_ind_wr(adapter, ms.wd[1], qlcnic_ind_rd(adapter, ms.rd[1]));
137462306a36Sopenharmony_ci	/* This is the write part of read-modify-write */
137562306a36Sopenharmony_ci	qlcnic_ind_wr(adapter, ms.wd[2], data & 0xffffffff);
137662306a36Sopenharmony_ci	qlcnic_ind_wr(adapter, ms.wd[3], (data >> 32) & 0xffffffff);
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci	qlcnic_ind_wr(adapter, ms.control, QLCNIC_TA_WRITE_ENABLE);
137962306a36Sopenharmony_ci	qlcnic_ind_wr(adapter, ms.control, QLCNIC_TA_WRITE_START);
138062306a36Sopenharmony_ci
138162306a36Sopenharmony_ci	for (j = 0; j < MAX_CTL_CHECK; j++) {
138262306a36Sopenharmony_ci		temp = qlcnic_ind_rd(adapter, ms.control);
138362306a36Sopenharmony_ci		if ((temp & TA_CTL_BUSY) == 0)
138462306a36Sopenharmony_ci			break;
138562306a36Sopenharmony_ci	}
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_ci	if (j >= MAX_CTL_CHECK) {
138862306a36Sopenharmony_ci		if (printk_ratelimit())
138962306a36Sopenharmony_ci			dev_err(&adapter->pdev->dev,
139062306a36Sopenharmony_ci					"failed to write through agent\n");
139162306a36Sopenharmony_ci		ret = -EIO;
139262306a36Sopenharmony_ci	} else
139362306a36Sopenharmony_ci		ret = 0;
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_cidone:
139662306a36Sopenharmony_ci	mutex_unlock(&adapter->ahw->mem_lock);
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	return ret;
139962306a36Sopenharmony_ci}
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ciint qlcnic_pci_mem_read_2M(struct qlcnic_adapter *adapter, u64 off, u64 *data)
140262306a36Sopenharmony_ci{
140362306a36Sopenharmony_ci	int j, ret;
140462306a36Sopenharmony_ci	u32 temp, off8;
140562306a36Sopenharmony_ci	u64 val;
140662306a36Sopenharmony_ci	struct qlcnic_ms_reg_ctrl ms;
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci	/* Only 64-bit aligned access */
140962306a36Sopenharmony_ci	if (off & 7)
141062306a36Sopenharmony_ci		return -EIO;
141162306a36Sopenharmony_ci	if (!(ADDR_IN_RANGE(off, QLCNIC_ADDR_QDR_NET,
141262306a36Sopenharmony_ci			    QLCNIC_ADDR_QDR_NET_MAX) ||
141362306a36Sopenharmony_ci	      ADDR_IN_RANGE(off, QLCNIC_ADDR_DDR_NET,
141462306a36Sopenharmony_ci			    QLCNIC_ADDR_DDR_NET_MAX)))
141562306a36Sopenharmony_ci		return -EIO;
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci	memset(&ms, 0, sizeof(struct qlcnic_ms_reg_ctrl));
141862306a36Sopenharmony_ci	qlcnic_set_ms_controls(adapter, off, &ms);
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci	if (ADDR_IN_RANGE(off, QLCNIC_ADDR_OCM0, QLCNIC_ADDR_OCM0_MAX))
142162306a36Sopenharmony_ci		return qlcnic_pci_mem_access_direct(adapter, ms.ocm_window,
142262306a36Sopenharmony_ci						    ms.off, data, 0);
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci	mutex_lock(&adapter->ahw->mem_lock);
142562306a36Sopenharmony_ci
142662306a36Sopenharmony_ci	off8 = off & ~0xf;
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_ci	qlcnic_ind_wr(adapter, ms.low, off8);
142962306a36Sopenharmony_ci	qlcnic_ind_wr(adapter, ms.hi, 0);
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci	qlcnic_ind_wr(adapter, ms.control, TA_CTL_ENABLE);
143262306a36Sopenharmony_ci	qlcnic_ind_wr(adapter, ms.control, QLCNIC_TA_START_ENABLE);
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci	for (j = 0; j < MAX_CTL_CHECK; j++) {
143562306a36Sopenharmony_ci		temp = qlcnic_ind_rd(adapter, ms.control);
143662306a36Sopenharmony_ci		if ((temp & TA_CTL_BUSY) == 0)
143762306a36Sopenharmony_ci			break;
143862306a36Sopenharmony_ci	}
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci	if (j >= MAX_CTL_CHECK) {
144162306a36Sopenharmony_ci		if (printk_ratelimit())
144262306a36Sopenharmony_ci			dev_err(&adapter->pdev->dev,
144362306a36Sopenharmony_ci					"failed to read through agent\n");
144462306a36Sopenharmony_ci		ret = -EIO;
144562306a36Sopenharmony_ci	} else {
144662306a36Sopenharmony_ci
144762306a36Sopenharmony_ci		temp = qlcnic_ind_rd(adapter, ms.rd[3]);
144862306a36Sopenharmony_ci		val = (u64)temp << 32;
144962306a36Sopenharmony_ci		val |= qlcnic_ind_rd(adapter, ms.rd[2]);
145062306a36Sopenharmony_ci		*data = val;
145162306a36Sopenharmony_ci		ret = 0;
145262306a36Sopenharmony_ci	}
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci	mutex_unlock(&adapter->ahw->mem_lock);
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_ci	return ret;
145762306a36Sopenharmony_ci}
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ciint qlcnic_82xx_get_board_info(struct qlcnic_adapter *adapter)
146062306a36Sopenharmony_ci{
146162306a36Sopenharmony_ci	int offset, board_type, magic, err = 0;
146262306a36Sopenharmony_ci	struct pci_dev *pdev = adapter->pdev;
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci	offset = QLCNIC_FW_MAGIC_OFFSET;
146562306a36Sopenharmony_ci	if (qlcnic_rom_fast_read(adapter, offset, &magic))
146662306a36Sopenharmony_ci		return -EIO;
146762306a36Sopenharmony_ci
146862306a36Sopenharmony_ci	if (magic != QLCNIC_BDINFO_MAGIC) {
146962306a36Sopenharmony_ci		dev_err(&pdev->dev, "invalid board config, magic=%08x\n",
147062306a36Sopenharmony_ci			magic);
147162306a36Sopenharmony_ci		return -EIO;
147262306a36Sopenharmony_ci	}
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci	offset = QLCNIC_BRDTYPE_OFFSET;
147562306a36Sopenharmony_ci	if (qlcnic_rom_fast_read(adapter, offset, &board_type))
147662306a36Sopenharmony_ci		return -EIO;
147762306a36Sopenharmony_ci
147862306a36Sopenharmony_ci	adapter->ahw->board_type = board_type;
147962306a36Sopenharmony_ci
148062306a36Sopenharmony_ci	if (board_type == QLCNIC_BRDTYPE_P3P_4_GB_MM) {
148162306a36Sopenharmony_ci		u32 gpio = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_PAD_GPIO_I, &err);
148262306a36Sopenharmony_ci		if (err == -EIO)
148362306a36Sopenharmony_ci			return err;
148462306a36Sopenharmony_ci		if ((gpio & 0x8000) == 0)
148562306a36Sopenharmony_ci			board_type = QLCNIC_BRDTYPE_P3P_10G_TP;
148662306a36Sopenharmony_ci	}
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci	switch (board_type) {
148962306a36Sopenharmony_ci	case QLCNIC_BRDTYPE_P3P_HMEZ:
149062306a36Sopenharmony_ci	case QLCNIC_BRDTYPE_P3P_XG_LOM:
149162306a36Sopenharmony_ci	case QLCNIC_BRDTYPE_P3P_10G_CX4:
149262306a36Sopenharmony_ci	case QLCNIC_BRDTYPE_P3P_10G_CX4_LP:
149362306a36Sopenharmony_ci	case QLCNIC_BRDTYPE_P3P_IMEZ:
149462306a36Sopenharmony_ci	case QLCNIC_BRDTYPE_P3P_10G_SFP_PLUS:
149562306a36Sopenharmony_ci	case QLCNIC_BRDTYPE_P3P_10G_SFP_CT:
149662306a36Sopenharmony_ci	case QLCNIC_BRDTYPE_P3P_10G_SFP_QT:
149762306a36Sopenharmony_ci	case QLCNIC_BRDTYPE_P3P_10G_XFP:
149862306a36Sopenharmony_ci	case QLCNIC_BRDTYPE_P3P_10000_BASE_T:
149962306a36Sopenharmony_ci		adapter->ahw->port_type = QLCNIC_XGBE;
150062306a36Sopenharmony_ci		break;
150162306a36Sopenharmony_ci	case QLCNIC_BRDTYPE_P3P_REF_QG:
150262306a36Sopenharmony_ci	case QLCNIC_BRDTYPE_P3P_4_GB:
150362306a36Sopenharmony_ci	case QLCNIC_BRDTYPE_P3P_4_GB_MM:
150462306a36Sopenharmony_ci		adapter->ahw->port_type = QLCNIC_GBE;
150562306a36Sopenharmony_ci		break;
150662306a36Sopenharmony_ci	case QLCNIC_BRDTYPE_P3P_10G_TP:
150762306a36Sopenharmony_ci		adapter->ahw->port_type = (adapter->portnum < 2) ?
150862306a36Sopenharmony_ci			QLCNIC_XGBE : QLCNIC_GBE;
150962306a36Sopenharmony_ci		break;
151062306a36Sopenharmony_ci	default:
151162306a36Sopenharmony_ci		dev_err(&pdev->dev, "unknown board type %x\n", board_type);
151262306a36Sopenharmony_ci		adapter->ahw->port_type = QLCNIC_XGBE;
151362306a36Sopenharmony_ci		break;
151462306a36Sopenharmony_ci	}
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci	return 0;
151762306a36Sopenharmony_ci}
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_cistatic int
152062306a36Sopenharmony_ciqlcnic_wol_supported(struct qlcnic_adapter *adapter)
152162306a36Sopenharmony_ci{
152262306a36Sopenharmony_ci	u32 wol_cfg;
152362306a36Sopenharmony_ci	int err = 0;
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci	wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV, &err);
152662306a36Sopenharmony_ci	if (wol_cfg & (1UL << adapter->portnum)) {
152762306a36Sopenharmony_ci		wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG, &err);
152862306a36Sopenharmony_ci		if (err == -EIO)
152962306a36Sopenharmony_ci			return err;
153062306a36Sopenharmony_ci		if (wol_cfg & (1 << adapter->portnum))
153162306a36Sopenharmony_ci			return 1;
153262306a36Sopenharmony_ci	}
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	return 0;
153562306a36Sopenharmony_ci}
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ciint qlcnic_82xx_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
153862306a36Sopenharmony_ci{
153962306a36Sopenharmony_ci	struct qlcnic_nic_req   req;
154062306a36Sopenharmony_ci	int rv;
154162306a36Sopenharmony_ci	u64 word;
154262306a36Sopenharmony_ci
154362306a36Sopenharmony_ci	memset(&req, 0, sizeof(struct qlcnic_nic_req));
154462306a36Sopenharmony_ci	req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	word = QLCNIC_H2C_OPCODE_CONFIG_LED | ((u64)adapter->portnum << 16);
154762306a36Sopenharmony_ci	req.req_hdr = cpu_to_le64(word);
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	req.words[0] = cpu_to_le64(((u64)rate << 32) | adapter->portnum);
155062306a36Sopenharmony_ci	req.words[1] = cpu_to_le64(state);
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci	rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
155362306a36Sopenharmony_ci	if (rv)
155462306a36Sopenharmony_ci		dev_err(&adapter->pdev->dev, "LED configuration failed.\n");
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci	return rv;
155762306a36Sopenharmony_ci}
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_civoid qlcnic_82xx_get_beacon_state(struct qlcnic_adapter *adapter)
156062306a36Sopenharmony_ci{
156162306a36Sopenharmony_ci	struct qlcnic_hardware_context *ahw = adapter->ahw;
156262306a36Sopenharmony_ci	struct qlcnic_cmd_args cmd;
156362306a36Sopenharmony_ci	u8 beacon_state;
156462306a36Sopenharmony_ci	int err = 0;
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci	if (ahw->extra_capability[0] & QLCNIC_FW_CAPABILITY_2_BEACON) {
156762306a36Sopenharmony_ci		err = qlcnic_alloc_mbx_args(&cmd, adapter,
156862306a36Sopenharmony_ci					    QLCNIC_CMD_GET_LED_STATUS);
156962306a36Sopenharmony_ci		if (!err) {
157062306a36Sopenharmony_ci			err = qlcnic_issue_cmd(adapter, &cmd);
157162306a36Sopenharmony_ci			if (err) {
157262306a36Sopenharmony_ci				netdev_err(adapter->netdev,
157362306a36Sopenharmony_ci					   "Failed to get current beacon state, err=%d\n",
157462306a36Sopenharmony_ci					   err);
157562306a36Sopenharmony_ci			} else {
157662306a36Sopenharmony_ci				beacon_state = cmd.rsp.arg[1];
157762306a36Sopenharmony_ci				if (beacon_state == QLCNIC_BEACON_DISABLE)
157862306a36Sopenharmony_ci					ahw->beacon_state = QLCNIC_BEACON_OFF;
157962306a36Sopenharmony_ci				else if (beacon_state == QLCNIC_BEACON_EANBLE)
158062306a36Sopenharmony_ci					ahw->beacon_state = QLCNIC_BEACON_ON;
158162306a36Sopenharmony_ci			}
158262306a36Sopenharmony_ci		}
158362306a36Sopenharmony_ci		qlcnic_free_mbx_args(&cmd);
158462306a36Sopenharmony_ci	}
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci	return;
158762306a36Sopenharmony_ci}
158862306a36Sopenharmony_ci
158962306a36Sopenharmony_civoid qlcnic_82xx_get_func_no(struct qlcnic_adapter *adapter)
159062306a36Sopenharmony_ci{
159162306a36Sopenharmony_ci	void __iomem *msix_base_addr;
159262306a36Sopenharmony_ci	u32 func;
159362306a36Sopenharmony_ci	u32 msix_base;
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_ci	pci_read_config_dword(adapter->pdev, QLCNIC_MSIX_TABLE_OFFSET, &func);
159662306a36Sopenharmony_ci	msix_base_addr = adapter->ahw->pci_base0 + QLCNIC_MSIX_BASE;
159762306a36Sopenharmony_ci	msix_base = readl(msix_base_addr);
159862306a36Sopenharmony_ci	func = (func - msix_base) / QLCNIC_MSIX_TBL_PGSIZE;
159962306a36Sopenharmony_ci	adapter->ahw->pci_func = func;
160062306a36Sopenharmony_ci}
160162306a36Sopenharmony_ci
160262306a36Sopenharmony_civoid qlcnic_82xx_read_crb(struct qlcnic_adapter *adapter, char *buf,
160362306a36Sopenharmony_ci			  loff_t offset, size_t size)
160462306a36Sopenharmony_ci{
160562306a36Sopenharmony_ci	int err = 0;
160662306a36Sopenharmony_ci	u32 data;
160762306a36Sopenharmony_ci	u64 qmdata;
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci	if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
161062306a36Sopenharmony_ci		qlcnic_pci_camqm_read_2M(adapter, offset, &qmdata);
161162306a36Sopenharmony_ci		memcpy(buf, &qmdata, size);
161262306a36Sopenharmony_ci	} else {
161362306a36Sopenharmony_ci		data = QLCRD32(adapter, offset, &err);
161462306a36Sopenharmony_ci		memcpy(buf, &data, size);
161562306a36Sopenharmony_ci	}
161662306a36Sopenharmony_ci}
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_civoid qlcnic_82xx_write_crb(struct qlcnic_adapter *adapter, char *buf,
161962306a36Sopenharmony_ci			   loff_t offset, size_t size)
162062306a36Sopenharmony_ci{
162162306a36Sopenharmony_ci	u32 data;
162262306a36Sopenharmony_ci	u64 qmdata;
162362306a36Sopenharmony_ci
162462306a36Sopenharmony_ci	if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
162562306a36Sopenharmony_ci		memcpy(&qmdata, buf, size);
162662306a36Sopenharmony_ci		qlcnic_pci_camqm_write_2M(adapter, offset, qmdata);
162762306a36Sopenharmony_ci	} else {
162862306a36Sopenharmony_ci		memcpy(&data, buf, size);
162962306a36Sopenharmony_ci		QLCWR32(adapter, offset, data);
163062306a36Sopenharmony_ci	}
163162306a36Sopenharmony_ci}
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_ciint qlcnic_82xx_api_lock(struct qlcnic_adapter *adapter)
163462306a36Sopenharmony_ci{
163562306a36Sopenharmony_ci	return qlcnic_pcie_sem_lock(adapter, 5, 0);
163662306a36Sopenharmony_ci}
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_civoid qlcnic_82xx_api_unlock(struct qlcnic_adapter *adapter)
163962306a36Sopenharmony_ci{
164062306a36Sopenharmony_ci	qlcnic_pcie_sem_unlock(adapter, 5);
164162306a36Sopenharmony_ci}
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ciint qlcnic_82xx_shutdown(struct pci_dev *pdev)
164462306a36Sopenharmony_ci{
164562306a36Sopenharmony_ci	struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
164662306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ci	netif_device_detach(netdev);
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci	qlcnic_cancel_idc_work(adapter);
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_ci	if (netif_running(netdev))
165362306a36Sopenharmony_ci		qlcnic_down(adapter, netdev);
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_ci	qlcnic_clr_all_drv_state(adapter, 0);
165662306a36Sopenharmony_ci
165762306a36Sopenharmony_ci	clear_bit(__QLCNIC_RESETTING, &adapter->state);
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci	if (qlcnic_wol_supported(adapter))
166062306a36Sopenharmony_ci		device_wakeup_enable(&pdev->dev);
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_ci	return 0;
166362306a36Sopenharmony_ci}
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_ciint qlcnic_82xx_resume(struct qlcnic_adapter *adapter)
166662306a36Sopenharmony_ci{
166762306a36Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
166862306a36Sopenharmony_ci	int err;
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_ci	err = qlcnic_start_firmware(adapter);
167162306a36Sopenharmony_ci	if (err) {
167262306a36Sopenharmony_ci		dev_err(&adapter->pdev->dev, "failed to start firmware\n");
167362306a36Sopenharmony_ci		return err;
167462306a36Sopenharmony_ci	}
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci	if (netif_running(netdev)) {
167762306a36Sopenharmony_ci		err = qlcnic_up(adapter, netdev);
167862306a36Sopenharmony_ci		if (!err)
167962306a36Sopenharmony_ci			qlcnic_restore_indev_addr(netdev, NETDEV_UP);
168062306a36Sopenharmony_ci	}
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_ci	netif_device_attach(netdev);
168362306a36Sopenharmony_ci	qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
168462306a36Sopenharmony_ci	return err;
168562306a36Sopenharmony_ci}
1686