18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * QLogic qlcnic NIC Driver
48c2ecf20Sopenharmony_ci * Copyright (c) 2009-2013 QLogic Corporation
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/slab.h>
88c2ecf20Sopenharmony_ci#include <net/ip.h>
98c2ecf20Sopenharmony_ci#include <linux/bitops.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include "qlcnic.h"
128c2ecf20Sopenharmony_ci#include "qlcnic_hdr.h"
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#define MASK(n) ((1ULL<<(n))-1)
158c2ecf20Sopenharmony_ci#define OCM_WIN_P3P(addr) (addr & 0xffc0000)
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#define GET_MEM_OFFS_2M(addr) (addr & MASK(18))
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#define CRB_BLK(off)	((off >> 20) & 0x3f)
208c2ecf20Sopenharmony_ci#define CRB_SUBBLK(off)	((off >> 16) & 0xf)
218c2ecf20Sopenharmony_ci#define CRB_WINDOW_2M	(0x130060)
228c2ecf20Sopenharmony_ci#define CRB_HI(off)	((crb_hub_agt[CRB_BLK(off)] << 20) | ((off) & 0xf0000))
238c2ecf20Sopenharmony_ci#define CRB_INDIRECT_2M	(0x1e0000UL)
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_cistruct qlcnic_ms_reg_ctrl {
268c2ecf20Sopenharmony_ci	u32 ocm_window;
278c2ecf20Sopenharmony_ci	u32 control;
288c2ecf20Sopenharmony_ci	u32 hi;
298c2ecf20Sopenharmony_ci	u32 low;
308c2ecf20Sopenharmony_ci	u32 rd[4];
318c2ecf20Sopenharmony_ci	u32 wd[4];
328c2ecf20Sopenharmony_ci	u64 off;
338c2ecf20Sopenharmony_ci};
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#ifndef readq
368c2ecf20Sopenharmony_cistatic inline u64 readq(void __iomem *addr)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	return readl(addr) | (((u64) readl(addr + 4)) << 32LL);
398c2ecf20Sopenharmony_ci}
408c2ecf20Sopenharmony_ci#endif
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci#ifndef writeq
438c2ecf20Sopenharmony_cistatic inline void writeq(u64 val, void __iomem *addr)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	writel(((u32) (val)), (addr));
468c2ecf20Sopenharmony_ci	writel(((u32) (val >> 32)), (addr + 4));
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci#endif
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_cistatic struct crb_128M_2M_block_map
518c2ecf20Sopenharmony_cicrb_128M_2M_map[64] __cacheline_aligned_in_smp = {
528c2ecf20Sopenharmony_ci    {{{0, 0,         0,         0} } },		/* 0: PCI */
538c2ecf20Sopenharmony_ci    {{{1, 0x0100000, 0x0102000, 0x120000},	/* 1: PCIE */
548c2ecf20Sopenharmony_ci	  {1, 0x0110000, 0x0120000, 0x130000},
558c2ecf20Sopenharmony_ci	  {1, 0x0120000, 0x0122000, 0x124000},
568c2ecf20Sopenharmony_ci	  {1, 0x0130000, 0x0132000, 0x126000},
578c2ecf20Sopenharmony_ci	  {1, 0x0140000, 0x0142000, 0x128000},
588c2ecf20Sopenharmony_ci	  {1, 0x0150000, 0x0152000, 0x12a000},
598c2ecf20Sopenharmony_ci	  {1, 0x0160000, 0x0170000, 0x110000},
608c2ecf20Sopenharmony_ci	  {1, 0x0170000, 0x0172000, 0x12e000},
618c2ecf20Sopenharmony_ci	  {0, 0x0000000, 0x0000000, 0x000000},
628c2ecf20Sopenharmony_ci	  {0, 0x0000000, 0x0000000, 0x000000},
638c2ecf20Sopenharmony_ci	  {0, 0x0000000, 0x0000000, 0x000000},
648c2ecf20Sopenharmony_ci	  {0, 0x0000000, 0x0000000, 0x000000},
658c2ecf20Sopenharmony_ci	  {0, 0x0000000, 0x0000000, 0x000000},
668c2ecf20Sopenharmony_ci	  {0, 0x0000000, 0x0000000, 0x000000},
678c2ecf20Sopenharmony_ci	  {1, 0x01e0000, 0x01e0800, 0x122000},
688c2ecf20Sopenharmony_ci	  {0, 0x0000000, 0x0000000, 0x000000} } },
698c2ecf20Sopenharmony_ci	{{{1, 0x0200000, 0x0210000, 0x180000} } },/* 2: MN */
708c2ecf20Sopenharmony_ci    {{{0, 0,         0,         0} } },	    /* 3: */
718c2ecf20Sopenharmony_ci    {{{1, 0x0400000, 0x0401000, 0x169000} } },/* 4: P2NR1 */
728c2ecf20Sopenharmony_ci    {{{1, 0x0500000, 0x0510000, 0x140000} } },/* 5: SRE   */
738c2ecf20Sopenharmony_ci    {{{1, 0x0600000, 0x0610000, 0x1c0000} } },/* 6: NIU   */
748c2ecf20Sopenharmony_ci    {{{1, 0x0700000, 0x0704000, 0x1b8000} } },/* 7: QM    */
758c2ecf20Sopenharmony_ci    {{{1, 0x0800000, 0x0802000, 0x170000},  /* 8: SQM0  */
768c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
778c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
788c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
798c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
808c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
818c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
828c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
838c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
848c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
858c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
868c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
878c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
888c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
898c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
908c2ecf20Sopenharmony_ci      {1, 0x08f0000, 0x08f2000, 0x172000} } },
918c2ecf20Sopenharmony_ci    {{{1, 0x0900000, 0x0902000, 0x174000},	/* 9: SQM1*/
928c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
938c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
948c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
958c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
968c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
978c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
988c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
998c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1008c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1018c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1028c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1038c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1048c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1058c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1068c2ecf20Sopenharmony_ci      {1, 0x09f0000, 0x09f2000, 0x176000} } },
1078c2ecf20Sopenharmony_ci    {{{0, 0x0a00000, 0x0a02000, 0x178000},	/* 10: SQM2*/
1088c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1098c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1108c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1118c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1128c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1138c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1148c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1158c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1168c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1178c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1188c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1198c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1208c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1218c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1228c2ecf20Sopenharmony_ci      {1, 0x0af0000, 0x0af2000, 0x17a000} } },
1238c2ecf20Sopenharmony_ci    {{{0, 0x0b00000, 0x0b02000, 0x17c000},	/* 11: SQM3*/
1248c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1258c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1268c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1278c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1288c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1298c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1308c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1318c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1328c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1338c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1348c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1358c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1368c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1378c2ecf20Sopenharmony_ci      {0, 0x0000000, 0x0000000, 0x000000},
1388c2ecf20Sopenharmony_ci      {1, 0x0bf0000, 0x0bf2000, 0x17e000} } },
1398c2ecf20Sopenharmony_ci	{{{1, 0x0c00000, 0x0c04000, 0x1d4000} } },/* 12: I2Q */
1408c2ecf20Sopenharmony_ci	{{{1, 0x0d00000, 0x0d04000, 0x1a4000} } },/* 13: TMR */
1418c2ecf20Sopenharmony_ci	{{{1, 0x0e00000, 0x0e04000, 0x1a0000} } },/* 14: ROMUSB */
1428c2ecf20Sopenharmony_ci	{{{1, 0x0f00000, 0x0f01000, 0x164000} } },/* 15: PEG4 */
1438c2ecf20Sopenharmony_ci	{{{0, 0x1000000, 0x1004000, 0x1a8000} } },/* 16: XDMA */
1448c2ecf20Sopenharmony_ci	{{{1, 0x1100000, 0x1101000, 0x160000} } },/* 17: PEG0 */
1458c2ecf20Sopenharmony_ci	{{{1, 0x1200000, 0x1201000, 0x161000} } },/* 18: PEG1 */
1468c2ecf20Sopenharmony_ci	{{{1, 0x1300000, 0x1301000, 0x162000} } },/* 19: PEG2 */
1478c2ecf20Sopenharmony_ci	{{{1, 0x1400000, 0x1401000, 0x163000} } },/* 20: PEG3 */
1488c2ecf20Sopenharmony_ci	{{{1, 0x1500000, 0x1501000, 0x165000} } },/* 21: P2ND */
1498c2ecf20Sopenharmony_ci	{{{1, 0x1600000, 0x1601000, 0x166000} } },/* 22: P2NI */
1508c2ecf20Sopenharmony_ci	{{{0, 0,         0,         0} } },	/* 23: */
1518c2ecf20Sopenharmony_ci	{{{0, 0,         0,         0} } },	/* 24: */
1528c2ecf20Sopenharmony_ci	{{{0, 0,         0,         0} } },	/* 25: */
1538c2ecf20Sopenharmony_ci	{{{0, 0,         0,         0} } },	/* 26: */
1548c2ecf20Sopenharmony_ci	{{{0, 0,         0,         0} } },	/* 27: */
1558c2ecf20Sopenharmony_ci	{{{0, 0,         0,         0} } },	/* 28: */
1568c2ecf20Sopenharmony_ci	{{{1, 0x1d00000, 0x1d10000, 0x190000} } },/* 29: MS */
1578c2ecf20Sopenharmony_ci    {{{1, 0x1e00000, 0x1e01000, 0x16a000} } },/* 30: P2NR2 */
1588c2ecf20Sopenharmony_ci    {{{1, 0x1f00000, 0x1f10000, 0x150000} } },/* 31: EPG */
1598c2ecf20Sopenharmony_ci	{{{0} } },				/* 32: PCI */
1608c2ecf20Sopenharmony_ci	{{{1, 0x2100000, 0x2102000, 0x120000},	/* 33: PCIE */
1618c2ecf20Sopenharmony_ci	  {1, 0x2110000, 0x2120000, 0x130000},
1628c2ecf20Sopenharmony_ci	  {1, 0x2120000, 0x2122000, 0x124000},
1638c2ecf20Sopenharmony_ci	  {1, 0x2130000, 0x2132000, 0x126000},
1648c2ecf20Sopenharmony_ci	  {1, 0x2140000, 0x2142000, 0x128000},
1658c2ecf20Sopenharmony_ci	  {1, 0x2150000, 0x2152000, 0x12a000},
1668c2ecf20Sopenharmony_ci	  {1, 0x2160000, 0x2170000, 0x110000},
1678c2ecf20Sopenharmony_ci	  {1, 0x2170000, 0x2172000, 0x12e000},
1688c2ecf20Sopenharmony_ci	  {0, 0x0000000, 0x0000000, 0x000000},
1698c2ecf20Sopenharmony_ci	  {0, 0x0000000, 0x0000000, 0x000000},
1708c2ecf20Sopenharmony_ci	  {0, 0x0000000, 0x0000000, 0x000000},
1718c2ecf20Sopenharmony_ci	  {0, 0x0000000, 0x0000000, 0x000000},
1728c2ecf20Sopenharmony_ci	  {0, 0x0000000, 0x0000000, 0x000000},
1738c2ecf20Sopenharmony_ci	  {0, 0x0000000, 0x0000000, 0x000000},
1748c2ecf20Sopenharmony_ci	  {0, 0x0000000, 0x0000000, 0x000000},
1758c2ecf20Sopenharmony_ci	  {0, 0x0000000, 0x0000000, 0x000000} } },
1768c2ecf20Sopenharmony_ci	{{{1, 0x2200000, 0x2204000, 0x1b0000} } },/* 34: CAM */
1778c2ecf20Sopenharmony_ci	{{{0} } },				/* 35: */
1788c2ecf20Sopenharmony_ci	{{{0} } },				/* 36: */
1798c2ecf20Sopenharmony_ci	{{{0} } },				/* 37: */
1808c2ecf20Sopenharmony_ci	{{{0} } },				/* 38: */
1818c2ecf20Sopenharmony_ci	{{{0} } },				/* 39: */
1828c2ecf20Sopenharmony_ci	{{{1, 0x2800000, 0x2804000, 0x1a4000} } },/* 40: TMR */
1838c2ecf20Sopenharmony_ci	{{{1, 0x2900000, 0x2901000, 0x16b000} } },/* 41: P2NR3 */
1848c2ecf20Sopenharmony_ci	{{{1, 0x2a00000, 0x2a00400, 0x1ac400} } },/* 42: RPMX1 */
1858c2ecf20Sopenharmony_ci	{{{1, 0x2b00000, 0x2b00400, 0x1ac800} } },/* 43: RPMX2 */
1868c2ecf20Sopenharmony_ci	{{{1, 0x2c00000, 0x2c00400, 0x1acc00} } },/* 44: RPMX3 */
1878c2ecf20Sopenharmony_ci	{{{1, 0x2d00000, 0x2d00400, 0x1ad000} } },/* 45: RPMX4 */
1888c2ecf20Sopenharmony_ci	{{{1, 0x2e00000, 0x2e00400, 0x1ad400} } },/* 46: RPMX5 */
1898c2ecf20Sopenharmony_ci	{{{1, 0x2f00000, 0x2f00400, 0x1ad800} } },/* 47: RPMX6 */
1908c2ecf20Sopenharmony_ci	{{{1, 0x3000000, 0x3000400, 0x1adc00} } },/* 48: RPMX7 */
1918c2ecf20Sopenharmony_ci	{{{0, 0x3100000, 0x3104000, 0x1a8000} } },/* 49: XDMA */
1928c2ecf20Sopenharmony_ci	{{{1, 0x3200000, 0x3204000, 0x1d4000} } },/* 50: I2Q */
1938c2ecf20Sopenharmony_ci	{{{1, 0x3300000, 0x3304000, 0x1a0000} } },/* 51: ROMUSB */
1948c2ecf20Sopenharmony_ci	{{{0} } },				/* 52: */
1958c2ecf20Sopenharmony_ci	{{{1, 0x3500000, 0x3500400, 0x1ac000} } },/* 53: RPMX0 */
1968c2ecf20Sopenharmony_ci	{{{1, 0x3600000, 0x3600400, 0x1ae000} } },/* 54: RPMX8 */
1978c2ecf20Sopenharmony_ci	{{{1, 0x3700000, 0x3700400, 0x1ae400} } },/* 55: RPMX9 */
1988c2ecf20Sopenharmony_ci	{{{1, 0x3800000, 0x3804000, 0x1d0000} } },/* 56: OCM0 */
1998c2ecf20Sopenharmony_ci	{{{1, 0x3900000, 0x3904000, 0x1b4000} } },/* 57: CRYPTO */
2008c2ecf20Sopenharmony_ci	{{{1, 0x3a00000, 0x3a04000, 0x1d8000} } },/* 58: SMB */
2018c2ecf20Sopenharmony_ci	{{{0} } },				/* 59: I2C0 */
2028c2ecf20Sopenharmony_ci	{{{0} } },				/* 60: I2C1 */
2038c2ecf20Sopenharmony_ci	{{{1, 0x3d00000, 0x3d04000, 0x1d8000} } },/* 61: LPC */
2048c2ecf20Sopenharmony_ci	{{{1, 0x3e00000, 0x3e01000, 0x167000} } },/* 62: P2NC */
2058c2ecf20Sopenharmony_ci	{{{1, 0x3f00000, 0x3f01000, 0x168000} } }	/* 63: P2NR0 */
2068c2ecf20Sopenharmony_ci};
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci/*
2098c2ecf20Sopenharmony_ci * top 12 bits of crb internal address (hub, agent)
2108c2ecf20Sopenharmony_ci */
2118c2ecf20Sopenharmony_cistatic const unsigned crb_hub_agt[64] = {
2128c2ecf20Sopenharmony_ci	0,
2138c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_PS,
2148c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_MN,
2158c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_MS,
2168c2ecf20Sopenharmony_ci	0,
2178c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_SRE,
2188c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_NIU,
2198c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_QMN,
2208c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_SQN0,
2218c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_SQN1,
2228c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_SQN2,
2238c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_SQN3,
2248c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_I2Q,
2258c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_TIMR,
2268c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_ROMUSB,
2278c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_PGN4,
2288c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_XDMA,
2298c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_PGN0,
2308c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_PGN1,
2318c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_PGN2,
2328c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_PGN3,
2338c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_PGND,
2348c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_PGNI,
2358c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_PGS0,
2368c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_PGS1,
2378c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_PGS2,
2388c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_PGS3,
2398c2ecf20Sopenharmony_ci	0,
2408c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_PGSI,
2418c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_SN,
2428c2ecf20Sopenharmony_ci	0,
2438c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_EG,
2448c2ecf20Sopenharmony_ci	0,
2458c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_PS,
2468c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_CAM,
2478c2ecf20Sopenharmony_ci	0,
2488c2ecf20Sopenharmony_ci	0,
2498c2ecf20Sopenharmony_ci	0,
2508c2ecf20Sopenharmony_ci	0,
2518c2ecf20Sopenharmony_ci	0,
2528c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_TIMR,
2538c2ecf20Sopenharmony_ci	0,
2548c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX1,
2558c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX2,
2568c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX3,
2578c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX4,
2588c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX5,
2598c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX6,
2608c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX7,
2618c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_XDMA,
2628c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_I2Q,
2638c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_ROMUSB,
2648c2ecf20Sopenharmony_ci	0,
2658c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX0,
2668c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX8,
2678c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_RPMX9,
2688c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_OCM0,
2698c2ecf20Sopenharmony_ci	0,
2708c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_SMB,
2718c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_I2C0,
2728c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_I2C1,
2738c2ecf20Sopenharmony_ci	0,
2748c2ecf20Sopenharmony_ci	QLCNIC_HW_CRB_HUB_AGT_ADR_PGNC,
2758c2ecf20Sopenharmony_ci	0,
2768c2ecf20Sopenharmony_ci};
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci/*  PCI Windowing for DDR regions.  */
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci#define QLCNIC_PCIE_SEM_TIMEOUT	10000
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_cistatic void qlcnic_read_window_reg(u32 addr, void __iomem *bar0, u32 *data)
2838c2ecf20Sopenharmony_ci{
2848c2ecf20Sopenharmony_ci	u32 dest;
2858c2ecf20Sopenharmony_ci	void __iomem *val;
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	dest = addr & 0xFFFF0000;
2888c2ecf20Sopenharmony_ci	val = bar0 + QLCNIC_FW_DUMP_REG1;
2898c2ecf20Sopenharmony_ci	writel(dest, val);
2908c2ecf20Sopenharmony_ci	readl(val);
2918c2ecf20Sopenharmony_ci	val = bar0 + QLCNIC_FW_DUMP_REG2 + LSW(addr);
2928c2ecf20Sopenharmony_ci	*data = readl(val);
2938c2ecf20Sopenharmony_ci}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_cistatic void qlcnic_write_window_reg(u32 addr, void __iomem *bar0, u32 data)
2968c2ecf20Sopenharmony_ci{
2978c2ecf20Sopenharmony_ci	u32 dest;
2988c2ecf20Sopenharmony_ci	void __iomem *val;
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	dest = addr & 0xFFFF0000;
3018c2ecf20Sopenharmony_ci	val = bar0 + QLCNIC_FW_DUMP_REG1;
3028c2ecf20Sopenharmony_ci	writel(dest, val);
3038c2ecf20Sopenharmony_ci	readl(val);
3048c2ecf20Sopenharmony_ci	val = bar0 + QLCNIC_FW_DUMP_REG2 + LSW(addr);
3058c2ecf20Sopenharmony_ci	writel(data, val);
3068c2ecf20Sopenharmony_ci	readl(val);
3078c2ecf20Sopenharmony_ci}
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ciint
3108c2ecf20Sopenharmony_ciqlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg)
3118c2ecf20Sopenharmony_ci{
3128c2ecf20Sopenharmony_ci	int timeout = 0, err = 0, done = 0;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	while (!done) {
3158c2ecf20Sopenharmony_ci		done = QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_LOCK(sem)),
3168c2ecf20Sopenharmony_ci			       &err);
3178c2ecf20Sopenharmony_ci		if (done == 1)
3188c2ecf20Sopenharmony_ci			break;
3198c2ecf20Sopenharmony_ci		if (++timeout >= QLCNIC_PCIE_SEM_TIMEOUT) {
3208c2ecf20Sopenharmony_ci			if (id_reg) {
3218c2ecf20Sopenharmony_ci				done = QLCRD32(adapter, id_reg, &err);
3228c2ecf20Sopenharmony_ci				if (done != -1)
3238c2ecf20Sopenharmony_ci					dev_err(&adapter->pdev->dev,
3248c2ecf20Sopenharmony_ci						"Failed to acquire sem=%d lock held by=%d\n",
3258c2ecf20Sopenharmony_ci						sem, done);
3268c2ecf20Sopenharmony_ci				else
3278c2ecf20Sopenharmony_ci					dev_err(&adapter->pdev->dev,
3288c2ecf20Sopenharmony_ci						"Failed to acquire sem=%d lock",
3298c2ecf20Sopenharmony_ci						sem);
3308c2ecf20Sopenharmony_ci			} else {
3318c2ecf20Sopenharmony_ci				dev_err(&adapter->pdev->dev,
3328c2ecf20Sopenharmony_ci					"Failed to acquire sem=%d lock", sem);
3338c2ecf20Sopenharmony_ci			}
3348c2ecf20Sopenharmony_ci			return -EIO;
3358c2ecf20Sopenharmony_ci		}
3368c2ecf20Sopenharmony_ci		udelay(1200);
3378c2ecf20Sopenharmony_ci	}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	if (id_reg)
3408c2ecf20Sopenharmony_ci		QLCWR32(adapter, id_reg, adapter->portnum);
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	return 0;
3438c2ecf20Sopenharmony_ci}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_civoid
3468c2ecf20Sopenharmony_ciqlcnic_pcie_sem_unlock(struct qlcnic_adapter *adapter, int sem)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	int err = 0;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_UNLOCK(sem)), &err);
3518c2ecf20Sopenharmony_ci}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ciint qlcnic_ind_rd(struct qlcnic_adapter *adapter, u32 addr)
3548c2ecf20Sopenharmony_ci{
3558c2ecf20Sopenharmony_ci	int err = 0;
3568c2ecf20Sopenharmony_ci	u32 data;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	if (qlcnic_82xx_check(adapter))
3598c2ecf20Sopenharmony_ci		qlcnic_read_window_reg(addr, adapter->ahw->pci_base0, &data);
3608c2ecf20Sopenharmony_ci	else {
3618c2ecf20Sopenharmony_ci		data = QLCRD32(adapter, addr, &err);
3628c2ecf20Sopenharmony_ci		if (err == -EIO)
3638c2ecf20Sopenharmony_ci			return err;
3648c2ecf20Sopenharmony_ci	}
3658c2ecf20Sopenharmony_ci	return data;
3668c2ecf20Sopenharmony_ci}
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ciint qlcnic_ind_wr(struct qlcnic_adapter *adapter, u32 addr, u32 data)
3698c2ecf20Sopenharmony_ci{
3708c2ecf20Sopenharmony_ci	int ret = 0;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	if (qlcnic_82xx_check(adapter))
3738c2ecf20Sopenharmony_ci		qlcnic_write_window_reg(addr, adapter->ahw->pci_base0, data);
3748c2ecf20Sopenharmony_ci	else
3758c2ecf20Sopenharmony_ci		ret = qlcnic_83xx_wrt_reg_indirect(adapter, addr, data);
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	return ret;
3788c2ecf20Sopenharmony_ci}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_cistatic int
3818c2ecf20Sopenharmony_ciqlcnic_send_cmd_descs(struct qlcnic_adapter *adapter,
3828c2ecf20Sopenharmony_ci		struct cmd_desc_type0 *cmd_desc_arr, int nr_desc)
3838c2ecf20Sopenharmony_ci{
3848c2ecf20Sopenharmony_ci	u32 i, producer;
3858c2ecf20Sopenharmony_ci	struct qlcnic_cmd_buffer *pbuf;
3868c2ecf20Sopenharmony_ci	struct cmd_desc_type0 *cmd_desc;
3878c2ecf20Sopenharmony_ci	struct qlcnic_host_tx_ring *tx_ring;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	i = 0;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))
3928c2ecf20Sopenharmony_ci		return -EIO;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	tx_ring = &adapter->tx_ring[0];
3958c2ecf20Sopenharmony_ci	__netif_tx_lock_bh(tx_ring->txq);
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	producer = tx_ring->producer;
3988c2ecf20Sopenharmony_ci
3998c2ecf20Sopenharmony_ci	if (nr_desc >= qlcnic_tx_avail(tx_ring)) {
4008c2ecf20Sopenharmony_ci		netif_tx_stop_queue(tx_ring->txq);
4018c2ecf20Sopenharmony_ci		smp_mb();
4028c2ecf20Sopenharmony_ci		if (qlcnic_tx_avail(tx_ring) > nr_desc) {
4038c2ecf20Sopenharmony_ci			if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH)
4048c2ecf20Sopenharmony_ci				netif_tx_wake_queue(tx_ring->txq);
4058c2ecf20Sopenharmony_ci		} else {
4068c2ecf20Sopenharmony_ci			adapter->stats.xmit_off++;
4078c2ecf20Sopenharmony_ci			__netif_tx_unlock_bh(tx_ring->txq);
4088c2ecf20Sopenharmony_ci			return -EBUSY;
4098c2ecf20Sopenharmony_ci		}
4108c2ecf20Sopenharmony_ci	}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	do {
4138c2ecf20Sopenharmony_ci		cmd_desc = &cmd_desc_arr[i];
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci		pbuf = &tx_ring->cmd_buf_arr[producer];
4168c2ecf20Sopenharmony_ci		pbuf->skb = NULL;
4178c2ecf20Sopenharmony_ci		pbuf->frag_count = 0;
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_ci		memcpy(&tx_ring->desc_head[producer],
4208c2ecf20Sopenharmony_ci		       cmd_desc, sizeof(struct cmd_desc_type0));
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci		producer = get_next_index(producer, tx_ring->num_desc);
4238c2ecf20Sopenharmony_ci		i++;
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci	} while (i != nr_desc);
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci	tx_ring->producer = producer;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	qlcnic_update_cmd_producer(tx_ring);
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	__netif_tx_unlock_bh(tx_ring->txq);
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	return 0;
4348c2ecf20Sopenharmony_ci}
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ciint qlcnic_82xx_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr,
4378c2ecf20Sopenharmony_ci				   u16 vlan_id, u8 op)
4388c2ecf20Sopenharmony_ci{
4398c2ecf20Sopenharmony_ci	struct qlcnic_nic_req req;
4408c2ecf20Sopenharmony_ci	struct qlcnic_mac_req *mac_req;
4418c2ecf20Sopenharmony_ci	struct qlcnic_vlan_req *vlan_req;
4428c2ecf20Sopenharmony_ci	u64 word;
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	memset(&req, 0, sizeof(struct qlcnic_nic_req));
4458c2ecf20Sopenharmony_ci	req.qhdr = cpu_to_le64(QLCNIC_REQUEST << 23);
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_ci	word = QLCNIC_MAC_EVENT | ((u64)adapter->portnum << 16);
4488c2ecf20Sopenharmony_ci	req.req_hdr = cpu_to_le64(word);
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_ci	mac_req = (struct qlcnic_mac_req *)&req.words[0];
4518c2ecf20Sopenharmony_ci	mac_req->op = op;
4528c2ecf20Sopenharmony_ci	memcpy(mac_req->mac_addr, addr, ETH_ALEN);
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	vlan_req = (struct qlcnic_vlan_req *)&req.words[1];
4558c2ecf20Sopenharmony_ci	vlan_req->vlan_id = cpu_to_le16(vlan_id);
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	return qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
4588c2ecf20Sopenharmony_ci}
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ciint qlcnic_nic_del_mac(struct qlcnic_adapter *adapter, const u8 *addr)
4618c2ecf20Sopenharmony_ci{
4628c2ecf20Sopenharmony_ci	struct qlcnic_mac_vlan_list *cur;
4638c2ecf20Sopenharmony_ci	struct list_head *head;
4648c2ecf20Sopenharmony_ci	int err = -EINVAL;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	/* Delete MAC from the existing list */
4678c2ecf20Sopenharmony_ci	list_for_each(head, &adapter->mac_list) {
4688c2ecf20Sopenharmony_ci		cur = list_entry(head, struct qlcnic_mac_vlan_list, list);
4698c2ecf20Sopenharmony_ci		if (ether_addr_equal(addr, cur->mac_addr)) {
4708c2ecf20Sopenharmony_ci			err = qlcnic_sre_macaddr_change(adapter, cur->mac_addr,
4718c2ecf20Sopenharmony_ci							0, QLCNIC_MAC_DEL);
4728c2ecf20Sopenharmony_ci			if (err)
4738c2ecf20Sopenharmony_ci				return err;
4748c2ecf20Sopenharmony_ci			list_del(&cur->list);
4758c2ecf20Sopenharmony_ci			kfree(cur);
4768c2ecf20Sopenharmony_ci			return err;
4778c2ecf20Sopenharmony_ci		}
4788c2ecf20Sopenharmony_ci	}
4798c2ecf20Sopenharmony_ci	return err;
4808c2ecf20Sopenharmony_ci}
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_ciint qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr, u16 vlan,
4838c2ecf20Sopenharmony_ci		       enum qlcnic_mac_type mac_type)
4848c2ecf20Sopenharmony_ci{
4858c2ecf20Sopenharmony_ci	struct qlcnic_mac_vlan_list *cur;
4868c2ecf20Sopenharmony_ci	struct list_head *head;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	/* look up if already exists */
4898c2ecf20Sopenharmony_ci	list_for_each(head, &adapter->mac_list) {
4908c2ecf20Sopenharmony_ci		cur = list_entry(head, struct qlcnic_mac_vlan_list, list);
4918c2ecf20Sopenharmony_ci		if (ether_addr_equal(addr, cur->mac_addr) &&
4928c2ecf20Sopenharmony_ci		    cur->vlan_id == vlan)
4938c2ecf20Sopenharmony_ci			return 0;
4948c2ecf20Sopenharmony_ci	}
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	cur = kzalloc(sizeof(*cur), GFP_ATOMIC);
4978c2ecf20Sopenharmony_ci	if (cur == NULL)
4988c2ecf20Sopenharmony_ci		return -ENOMEM;
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	memcpy(cur->mac_addr, addr, ETH_ALEN);
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	if (qlcnic_sre_macaddr_change(adapter,
5038c2ecf20Sopenharmony_ci				cur->mac_addr, vlan, QLCNIC_MAC_ADD)) {
5048c2ecf20Sopenharmony_ci		kfree(cur);
5058c2ecf20Sopenharmony_ci		return -EIO;
5068c2ecf20Sopenharmony_ci	}
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	cur->vlan_id = vlan;
5098c2ecf20Sopenharmony_ci	cur->mac_type = mac_type;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	list_add_tail(&cur->list, &adapter->mac_list);
5128c2ecf20Sopenharmony_ci	return 0;
5138c2ecf20Sopenharmony_ci}
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_civoid qlcnic_flush_mcast_mac(struct qlcnic_adapter *adapter)
5168c2ecf20Sopenharmony_ci{
5178c2ecf20Sopenharmony_ci	struct qlcnic_mac_vlan_list *cur;
5188c2ecf20Sopenharmony_ci	struct list_head *head, *tmp;
5198c2ecf20Sopenharmony_ci
5208c2ecf20Sopenharmony_ci	list_for_each_safe(head, tmp, &adapter->mac_list) {
5218c2ecf20Sopenharmony_ci		cur = list_entry(head, struct qlcnic_mac_vlan_list, list);
5228c2ecf20Sopenharmony_ci		if (cur->mac_type != QLCNIC_MULTICAST_MAC)
5238c2ecf20Sopenharmony_ci			continue;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci		qlcnic_sre_macaddr_change(adapter, cur->mac_addr,
5268c2ecf20Sopenharmony_ci					  cur->vlan_id, QLCNIC_MAC_DEL);
5278c2ecf20Sopenharmony_ci		list_del(&cur->list);
5288c2ecf20Sopenharmony_ci		kfree(cur);
5298c2ecf20Sopenharmony_ci	}
5308c2ecf20Sopenharmony_ci}
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_cistatic void __qlcnic_set_multi(struct net_device *netdev, u16 vlan)
5338c2ecf20Sopenharmony_ci{
5348c2ecf20Sopenharmony_ci	struct qlcnic_adapter *adapter = netdev_priv(netdev);
5358c2ecf20Sopenharmony_ci	struct qlcnic_hardware_context *ahw = adapter->ahw;
5368c2ecf20Sopenharmony_ci	struct netdev_hw_addr *ha;
5378c2ecf20Sopenharmony_ci	static const u8 bcast_addr[ETH_ALEN] = {
5388c2ecf20Sopenharmony_ci		0xff, 0xff, 0xff, 0xff, 0xff, 0xff
5398c2ecf20Sopenharmony_ci	};
5408c2ecf20Sopenharmony_ci	u32 mode = VPORT_MISS_MODE_DROP;
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))
5438c2ecf20Sopenharmony_ci		return;
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	qlcnic_nic_add_mac(adapter, adapter->mac_addr, vlan,
5468c2ecf20Sopenharmony_ci			   QLCNIC_UNICAST_MAC);
5478c2ecf20Sopenharmony_ci	qlcnic_nic_add_mac(adapter, bcast_addr, vlan, QLCNIC_BROADCAST_MAC);
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	if (netdev->flags & IFF_PROMISC) {
5508c2ecf20Sopenharmony_ci		if (!(adapter->flags & QLCNIC_PROMISC_DISABLED))
5518c2ecf20Sopenharmony_ci			mode = VPORT_MISS_MODE_ACCEPT_ALL;
5528c2ecf20Sopenharmony_ci	} else if ((netdev->flags & IFF_ALLMULTI) ||
5538c2ecf20Sopenharmony_ci		   (netdev_mc_count(netdev) > ahw->max_mc_count)) {
5548c2ecf20Sopenharmony_ci		mode = VPORT_MISS_MODE_ACCEPT_MULTI;
5558c2ecf20Sopenharmony_ci	} else if (!netdev_mc_empty(netdev)) {
5568c2ecf20Sopenharmony_ci		qlcnic_flush_mcast_mac(adapter);
5578c2ecf20Sopenharmony_ci		netdev_for_each_mc_addr(ha, netdev)
5588c2ecf20Sopenharmony_ci			qlcnic_nic_add_mac(adapter, ha->addr, vlan,
5598c2ecf20Sopenharmony_ci					   QLCNIC_MULTICAST_MAC);
5608c2ecf20Sopenharmony_ci	}
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	/* configure unicast MAC address, if there is not sufficient space
5638c2ecf20Sopenharmony_ci	 * to store all the unicast addresses then enable promiscuous mode
5648c2ecf20Sopenharmony_ci	 */
5658c2ecf20Sopenharmony_ci	if (netdev_uc_count(netdev) > ahw->max_uc_count) {
5668c2ecf20Sopenharmony_ci		mode = VPORT_MISS_MODE_ACCEPT_ALL;
5678c2ecf20Sopenharmony_ci	} else if (!netdev_uc_empty(netdev)) {
5688c2ecf20Sopenharmony_ci		netdev_for_each_uc_addr(ha, netdev)
5698c2ecf20Sopenharmony_ci			qlcnic_nic_add_mac(adapter, ha->addr, vlan,
5708c2ecf20Sopenharmony_ci					   QLCNIC_UNICAST_MAC);
5718c2ecf20Sopenharmony_ci	}
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_ci	if (mode == VPORT_MISS_MODE_ACCEPT_ALL &&
5748c2ecf20Sopenharmony_ci	    !adapter->fdb_mac_learn) {
5758c2ecf20Sopenharmony_ci		qlcnic_alloc_lb_filters_mem(adapter);
5768c2ecf20Sopenharmony_ci		adapter->drv_mac_learn = 1;
5778c2ecf20Sopenharmony_ci		if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
5788c2ecf20Sopenharmony_ci			adapter->rx_mac_learn = true;
5798c2ecf20Sopenharmony_ci	} else {
5808c2ecf20Sopenharmony_ci		adapter->drv_mac_learn = 0;
5818c2ecf20Sopenharmony_ci		adapter->rx_mac_learn = false;
5828c2ecf20Sopenharmony_ci	}
5838c2ecf20Sopenharmony_ci
5848c2ecf20Sopenharmony_ci	qlcnic_nic_set_promisc(adapter, mode);
5858c2ecf20Sopenharmony_ci}
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_civoid qlcnic_set_multi(struct net_device *netdev)
5888c2ecf20Sopenharmony_ci{
5898c2ecf20Sopenharmony_ci	struct qlcnic_adapter *adapter = netdev_priv(netdev);
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))
5928c2ecf20Sopenharmony_ci		return;
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci	if (qlcnic_sriov_vf_check(adapter))
5958c2ecf20Sopenharmony_ci		qlcnic_sriov_vf_set_multi(netdev);
5968c2ecf20Sopenharmony_ci	else
5978c2ecf20Sopenharmony_ci		__qlcnic_set_multi(netdev, 0);
5988c2ecf20Sopenharmony_ci}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ciint qlcnic_82xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode)
6018c2ecf20Sopenharmony_ci{
6028c2ecf20Sopenharmony_ci	struct qlcnic_nic_req req;
6038c2ecf20Sopenharmony_ci	u64 word;
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	memset(&req, 0, sizeof(struct qlcnic_nic_req));
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	word = QLCNIC_H2C_OPCODE_SET_MAC_RECEIVE_MODE |
6108c2ecf20Sopenharmony_ci			((u64)adapter->portnum << 16);
6118c2ecf20Sopenharmony_ci	req.req_hdr = cpu_to_le64(word);
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	req.words[0] = cpu_to_le64(mode);
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_ci	return qlcnic_send_cmd_descs(adapter,
6168c2ecf20Sopenharmony_ci				(struct cmd_desc_type0 *)&req, 1);
6178c2ecf20Sopenharmony_ci}
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_civoid qlcnic_82xx_free_mac_list(struct qlcnic_adapter *adapter)
6208c2ecf20Sopenharmony_ci{
6218c2ecf20Sopenharmony_ci	struct list_head *head = &adapter->mac_list;
6228c2ecf20Sopenharmony_ci	struct qlcnic_mac_vlan_list *cur;
6238c2ecf20Sopenharmony_ci
6248c2ecf20Sopenharmony_ci	while (!list_empty(head)) {
6258c2ecf20Sopenharmony_ci		cur = list_entry(head->next, struct qlcnic_mac_vlan_list, list);
6268c2ecf20Sopenharmony_ci		qlcnic_sre_macaddr_change(adapter,
6278c2ecf20Sopenharmony_ci				cur->mac_addr, 0, QLCNIC_MAC_DEL);
6288c2ecf20Sopenharmony_ci		list_del(&cur->list);
6298c2ecf20Sopenharmony_ci		kfree(cur);
6308c2ecf20Sopenharmony_ci	}
6318c2ecf20Sopenharmony_ci}
6328c2ecf20Sopenharmony_ci
6338c2ecf20Sopenharmony_civoid qlcnic_prune_lb_filters(struct qlcnic_adapter *adapter)
6348c2ecf20Sopenharmony_ci{
6358c2ecf20Sopenharmony_ci	struct qlcnic_filter *tmp_fil;
6368c2ecf20Sopenharmony_ci	struct hlist_node *n;
6378c2ecf20Sopenharmony_ci	struct hlist_head *head;
6388c2ecf20Sopenharmony_ci	int i;
6398c2ecf20Sopenharmony_ci	unsigned long expires;
6408c2ecf20Sopenharmony_ci	u8 cmd;
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	for (i = 0; i < adapter->fhash.fbucket_size; i++) {
6438c2ecf20Sopenharmony_ci		head = &(adapter->fhash.fhead[i]);
6448c2ecf20Sopenharmony_ci		hlist_for_each_entry_safe(tmp_fil, n, head, fnode) {
6458c2ecf20Sopenharmony_ci			cmd =  tmp_fil->vlan_id ? QLCNIC_MAC_VLAN_DEL :
6468c2ecf20Sopenharmony_ci						  QLCNIC_MAC_DEL;
6478c2ecf20Sopenharmony_ci			expires = tmp_fil->ftime + QLCNIC_FILTER_AGE * HZ;
6488c2ecf20Sopenharmony_ci			if (time_before(expires, jiffies)) {
6498c2ecf20Sopenharmony_ci				qlcnic_sre_macaddr_change(adapter,
6508c2ecf20Sopenharmony_ci							  tmp_fil->faddr,
6518c2ecf20Sopenharmony_ci							  tmp_fil->vlan_id,
6528c2ecf20Sopenharmony_ci							  cmd);
6538c2ecf20Sopenharmony_ci				spin_lock_bh(&adapter->mac_learn_lock);
6548c2ecf20Sopenharmony_ci				adapter->fhash.fnum--;
6558c2ecf20Sopenharmony_ci				hlist_del(&tmp_fil->fnode);
6568c2ecf20Sopenharmony_ci				spin_unlock_bh(&adapter->mac_learn_lock);
6578c2ecf20Sopenharmony_ci				kfree(tmp_fil);
6588c2ecf20Sopenharmony_ci			}
6598c2ecf20Sopenharmony_ci		}
6608c2ecf20Sopenharmony_ci	}
6618c2ecf20Sopenharmony_ci	for (i = 0; i < adapter->rx_fhash.fbucket_size; i++) {
6628c2ecf20Sopenharmony_ci		head = &(adapter->rx_fhash.fhead[i]);
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci		hlist_for_each_entry_safe(tmp_fil, n, head, fnode)
6658c2ecf20Sopenharmony_ci		{
6668c2ecf20Sopenharmony_ci			expires = tmp_fil->ftime + QLCNIC_FILTER_AGE * HZ;
6678c2ecf20Sopenharmony_ci			if (time_before(expires, jiffies)) {
6688c2ecf20Sopenharmony_ci				spin_lock_bh(&adapter->rx_mac_learn_lock);
6698c2ecf20Sopenharmony_ci				adapter->rx_fhash.fnum--;
6708c2ecf20Sopenharmony_ci				hlist_del(&tmp_fil->fnode);
6718c2ecf20Sopenharmony_ci				spin_unlock_bh(&adapter->rx_mac_learn_lock);
6728c2ecf20Sopenharmony_ci				kfree(tmp_fil);
6738c2ecf20Sopenharmony_ci			}
6748c2ecf20Sopenharmony_ci		}
6758c2ecf20Sopenharmony_ci	}
6768c2ecf20Sopenharmony_ci}
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_civoid qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter)
6798c2ecf20Sopenharmony_ci{
6808c2ecf20Sopenharmony_ci	struct qlcnic_filter *tmp_fil;
6818c2ecf20Sopenharmony_ci	struct hlist_node *n;
6828c2ecf20Sopenharmony_ci	struct hlist_head *head;
6838c2ecf20Sopenharmony_ci	int i;
6848c2ecf20Sopenharmony_ci	u8 cmd;
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	for (i = 0; i < adapter->fhash.fbucket_size; i++) {
6878c2ecf20Sopenharmony_ci		head = &(adapter->fhash.fhead[i]);
6888c2ecf20Sopenharmony_ci		hlist_for_each_entry_safe(tmp_fil, n, head, fnode) {
6898c2ecf20Sopenharmony_ci			cmd =  tmp_fil->vlan_id ? QLCNIC_MAC_VLAN_DEL :
6908c2ecf20Sopenharmony_ci						  QLCNIC_MAC_DEL;
6918c2ecf20Sopenharmony_ci			qlcnic_sre_macaddr_change(adapter,
6928c2ecf20Sopenharmony_ci						  tmp_fil->faddr,
6938c2ecf20Sopenharmony_ci						  tmp_fil->vlan_id,
6948c2ecf20Sopenharmony_ci						  cmd);
6958c2ecf20Sopenharmony_ci			spin_lock_bh(&adapter->mac_learn_lock);
6968c2ecf20Sopenharmony_ci			adapter->fhash.fnum--;
6978c2ecf20Sopenharmony_ci			hlist_del(&tmp_fil->fnode);
6988c2ecf20Sopenharmony_ci			spin_unlock_bh(&adapter->mac_learn_lock);
6998c2ecf20Sopenharmony_ci			kfree(tmp_fil);
7008c2ecf20Sopenharmony_ci		}
7018c2ecf20Sopenharmony_ci	}
7028c2ecf20Sopenharmony_ci}
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_cistatic int qlcnic_set_fw_loopback(struct qlcnic_adapter *adapter, u8 flag)
7058c2ecf20Sopenharmony_ci{
7068c2ecf20Sopenharmony_ci	struct qlcnic_nic_req req;
7078c2ecf20Sopenharmony_ci	int rv;
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	memset(&req, 0, sizeof(struct qlcnic_nic_req));
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci	req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
7128c2ecf20Sopenharmony_ci	req.req_hdr = cpu_to_le64(QLCNIC_H2C_OPCODE_CONFIG_LOOPBACK |
7138c2ecf20Sopenharmony_ci		((u64) adapter->portnum << 16) | ((u64) 0x1 << 32));
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	req.words[0] = cpu_to_le64(flag);
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
7188c2ecf20Sopenharmony_ci	if (rv != 0)
7198c2ecf20Sopenharmony_ci		dev_err(&adapter->pdev->dev, "%sting loopback mode failed\n",
7208c2ecf20Sopenharmony_ci				flag ? "Set" : "Reset");
7218c2ecf20Sopenharmony_ci	return rv;
7228c2ecf20Sopenharmony_ci}
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ciint qlcnic_82xx_set_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
7258c2ecf20Sopenharmony_ci{
7268c2ecf20Sopenharmony_ci	if (qlcnic_set_fw_loopback(adapter, mode))
7278c2ecf20Sopenharmony_ci		return -EIO;
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci	if (qlcnic_nic_set_promisc(adapter,
7308c2ecf20Sopenharmony_ci				   VPORT_MISS_MODE_ACCEPT_ALL)) {
7318c2ecf20Sopenharmony_ci		qlcnic_set_fw_loopback(adapter, 0);
7328c2ecf20Sopenharmony_ci		return -EIO;
7338c2ecf20Sopenharmony_ci	}
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	msleep(1000);
7368c2ecf20Sopenharmony_ci	return 0;
7378c2ecf20Sopenharmony_ci}
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ciint qlcnic_82xx_clear_lb_mode(struct qlcnic_adapter *adapter, u8 mode)
7408c2ecf20Sopenharmony_ci{
7418c2ecf20Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	mode = VPORT_MISS_MODE_DROP;
7448c2ecf20Sopenharmony_ci	qlcnic_set_fw_loopback(adapter, 0);
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	if (netdev->flags & IFF_PROMISC)
7478c2ecf20Sopenharmony_ci		mode = VPORT_MISS_MODE_ACCEPT_ALL;
7488c2ecf20Sopenharmony_ci	else if (netdev->flags & IFF_ALLMULTI)
7498c2ecf20Sopenharmony_ci		mode = VPORT_MISS_MODE_ACCEPT_MULTI;
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	qlcnic_nic_set_promisc(adapter, mode);
7528c2ecf20Sopenharmony_ci	msleep(1000);
7538c2ecf20Sopenharmony_ci	return 0;
7548c2ecf20Sopenharmony_ci}
7558c2ecf20Sopenharmony_ci
7568c2ecf20Sopenharmony_ciint qlcnic_82xx_read_phys_port_id(struct qlcnic_adapter *adapter)
7578c2ecf20Sopenharmony_ci{
7588c2ecf20Sopenharmony_ci	u8 mac[ETH_ALEN];
7598c2ecf20Sopenharmony_ci	int ret;
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	ret = qlcnic_get_mac_address(adapter, mac,
7628c2ecf20Sopenharmony_ci				     adapter->ahw->physical_port);
7638c2ecf20Sopenharmony_ci	if (ret)
7648c2ecf20Sopenharmony_ci		return ret;
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	memcpy(adapter->ahw->phys_port_id, mac, ETH_ALEN);
7678c2ecf20Sopenharmony_ci	adapter->flags |= QLCNIC_HAS_PHYS_PORT_ID;
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci	return 0;
7708c2ecf20Sopenharmony_ci}
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ciint qlcnic_82xx_set_rx_coalesce(struct qlcnic_adapter *adapter)
7738c2ecf20Sopenharmony_ci{
7748c2ecf20Sopenharmony_ci	struct qlcnic_nic_req req;
7758c2ecf20Sopenharmony_ci	int rv;
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci	memset(&req, 0, sizeof(struct qlcnic_nic_req));
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_ci	req.req_hdr = cpu_to_le64(QLCNIC_CONFIG_INTR_COALESCE |
7828c2ecf20Sopenharmony_ci		((u64) adapter->portnum << 16));
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	req.words[0] = cpu_to_le64(((u64) adapter->ahw->coal.flag) << 32);
7858c2ecf20Sopenharmony_ci	req.words[2] = cpu_to_le64(adapter->ahw->coal.rx_packets |
7868c2ecf20Sopenharmony_ci			((u64) adapter->ahw->coal.rx_time_us) << 16);
7878c2ecf20Sopenharmony_ci	req.words[5] = cpu_to_le64(adapter->ahw->coal.timer_out |
7888c2ecf20Sopenharmony_ci			((u64) adapter->ahw->coal.type) << 32 |
7898c2ecf20Sopenharmony_ci			((u64) adapter->ahw->coal.sts_ring_mask) << 40);
7908c2ecf20Sopenharmony_ci	rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
7918c2ecf20Sopenharmony_ci	if (rv != 0)
7928c2ecf20Sopenharmony_ci		dev_err(&adapter->netdev->dev,
7938c2ecf20Sopenharmony_ci			"Could not send interrupt coalescing parameters\n");
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	return rv;
7968c2ecf20Sopenharmony_ci}
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci/* Send the interrupt coalescing parameter set by ethtool to the card. */
7998c2ecf20Sopenharmony_ciint qlcnic_82xx_config_intr_coalesce(struct qlcnic_adapter *adapter,
8008c2ecf20Sopenharmony_ci				     struct ethtool_coalesce *ethcoal)
8018c2ecf20Sopenharmony_ci{
8028c2ecf20Sopenharmony_ci	struct qlcnic_nic_intr_coalesce *coal = &adapter->ahw->coal;
8038c2ecf20Sopenharmony_ci	int rv;
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	coal->flag = QLCNIC_INTR_DEFAULT;
8068c2ecf20Sopenharmony_ci	coal->rx_time_us = ethcoal->rx_coalesce_usecs;
8078c2ecf20Sopenharmony_ci	coal->rx_packets = ethcoal->rx_max_coalesced_frames;
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci	rv = qlcnic_82xx_set_rx_coalesce(adapter);
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	if (rv)
8128c2ecf20Sopenharmony_ci		netdev_err(adapter->netdev,
8138c2ecf20Sopenharmony_ci			   "Failed to set Rx coalescing parameters\n");
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_ci	return rv;
8168c2ecf20Sopenharmony_ci}
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci#define QLCNIC_ENABLE_IPV4_LRO		BIT_0
8198c2ecf20Sopenharmony_ci#define QLCNIC_ENABLE_IPV6_LRO		(BIT_1 | BIT_9)
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ciint qlcnic_82xx_config_hw_lro(struct qlcnic_adapter *adapter, int enable)
8228c2ecf20Sopenharmony_ci{
8238c2ecf20Sopenharmony_ci	struct qlcnic_nic_req req;
8248c2ecf20Sopenharmony_ci	u64 word;
8258c2ecf20Sopenharmony_ci	int rv;
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci	if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))
8288c2ecf20Sopenharmony_ci		return 0;
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	memset(&req, 0, sizeof(struct qlcnic_nic_req));
8318c2ecf20Sopenharmony_ci
8328c2ecf20Sopenharmony_ci	req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	word = QLCNIC_H2C_OPCODE_CONFIG_HW_LRO | ((u64)adapter->portnum << 16);
8358c2ecf20Sopenharmony_ci	req.req_hdr = cpu_to_le64(word);
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	word = 0;
8388c2ecf20Sopenharmony_ci	if (enable) {
8398c2ecf20Sopenharmony_ci		word = QLCNIC_ENABLE_IPV4_LRO;
8408c2ecf20Sopenharmony_ci		if (adapter->ahw->extra_capability[0] &
8418c2ecf20Sopenharmony_ci		    QLCNIC_FW_CAP2_HW_LRO_IPV6)
8428c2ecf20Sopenharmony_ci			word |= QLCNIC_ENABLE_IPV6_LRO;
8438c2ecf20Sopenharmony_ci	}
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	req.words[0] = cpu_to_le64(word);
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
8488c2ecf20Sopenharmony_ci	if (rv != 0)
8498c2ecf20Sopenharmony_ci		dev_err(&adapter->netdev->dev,
8508c2ecf20Sopenharmony_ci			"Could not send configure hw lro request\n");
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	return rv;
8538c2ecf20Sopenharmony_ci}
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ciint qlcnic_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable)
8568c2ecf20Sopenharmony_ci{
8578c2ecf20Sopenharmony_ci	struct qlcnic_nic_req req;
8588c2ecf20Sopenharmony_ci	u64 word;
8598c2ecf20Sopenharmony_ci	int rv;
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci	if (!!(adapter->flags & QLCNIC_BRIDGE_ENABLED) == enable)
8628c2ecf20Sopenharmony_ci		return 0;
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci	memset(&req, 0, sizeof(struct qlcnic_nic_req));
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	word = QLCNIC_H2C_OPCODE_CONFIG_BRIDGING |
8698c2ecf20Sopenharmony_ci		((u64)adapter->portnum << 16);
8708c2ecf20Sopenharmony_ci	req.req_hdr = cpu_to_le64(word);
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	req.words[0] = cpu_to_le64(enable);
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
8758c2ecf20Sopenharmony_ci	if (rv != 0)
8768c2ecf20Sopenharmony_ci		dev_err(&adapter->netdev->dev,
8778c2ecf20Sopenharmony_ci			"Could not send configure bridge mode request\n");
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	adapter->flags ^= QLCNIC_BRIDGE_ENABLED;
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci	return rv;
8828c2ecf20Sopenharmony_ci}
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci#define QLCNIC_RSS_HASHTYPE_IP_TCP	0x3
8868c2ecf20Sopenharmony_ci#define QLCNIC_ENABLE_TYPE_C_RSS	BIT_10
8878c2ecf20Sopenharmony_ci#define QLCNIC_RSS_FEATURE_FLAG	(1ULL << 63)
8888c2ecf20Sopenharmony_ci#define QLCNIC_RSS_IND_TABLE_MASK	0x7ULL
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ciint qlcnic_82xx_config_rss(struct qlcnic_adapter *adapter, int enable)
8918c2ecf20Sopenharmony_ci{
8928c2ecf20Sopenharmony_ci	struct qlcnic_nic_req req;
8938c2ecf20Sopenharmony_ci	u64 word;
8948c2ecf20Sopenharmony_ci	int i, rv;
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	static const u64 key[] = {
8978c2ecf20Sopenharmony_ci		0xbeac01fa6a42b73bULL, 0x8030f20c77cb2da3ULL,
8988c2ecf20Sopenharmony_ci		0xae7b30b4d0ca2bcbULL, 0x43a38fb04167253dULL,
8998c2ecf20Sopenharmony_ci		0x255b0ec26d5a56daULL
9008c2ecf20Sopenharmony_ci	};
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	memset(&req, 0, sizeof(struct qlcnic_nic_req));
9038c2ecf20Sopenharmony_ci	req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	word = QLCNIC_H2C_OPCODE_CONFIG_RSS | ((u64)adapter->portnum << 16);
9068c2ecf20Sopenharmony_ci	req.req_hdr = cpu_to_le64(word);
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci	/*
9098c2ecf20Sopenharmony_ci	 * RSS request:
9108c2ecf20Sopenharmony_ci	 * bits 3-0: hash_method
9118c2ecf20Sopenharmony_ci	 *      5-4: hash_type_ipv4
9128c2ecf20Sopenharmony_ci	 *	7-6: hash_type_ipv6
9138c2ecf20Sopenharmony_ci	 *	  8: enable
9148c2ecf20Sopenharmony_ci	 *        9: use indirection table
9158c2ecf20Sopenharmony_ci	 *       10: type-c rss
9168c2ecf20Sopenharmony_ci	 *	 11: udp rss
9178c2ecf20Sopenharmony_ci	 *    47-12: reserved
9188c2ecf20Sopenharmony_ci	 *    62-48: indirection table mask
9198c2ecf20Sopenharmony_ci	 *	 63: feature flag
9208c2ecf20Sopenharmony_ci	 */
9218c2ecf20Sopenharmony_ci	word =  ((u64)(QLCNIC_RSS_HASHTYPE_IP_TCP & 0x3) << 4) |
9228c2ecf20Sopenharmony_ci		((u64)(QLCNIC_RSS_HASHTYPE_IP_TCP & 0x3) << 6) |
9238c2ecf20Sopenharmony_ci		((u64)(enable & 0x1) << 8) |
9248c2ecf20Sopenharmony_ci		((u64)QLCNIC_RSS_IND_TABLE_MASK << 48) |
9258c2ecf20Sopenharmony_ci		(u64)QLCNIC_ENABLE_TYPE_C_RSS |
9268c2ecf20Sopenharmony_ci		(u64)QLCNIC_RSS_FEATURE_FLAG;
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ci	req.words[0] = cpu_to_le64(word);
9298c2ecf20Sopenharmony_ci	for (i = 0; i < 5; i++)
9308c2ecf20Sopenharmony_ci		req.words[i+1] = cpu_to_le64(key[i]);
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
9338c2ecf20Sopenharmony_ci	if (rv != 0)
9348c2ecf20Sopenharmony_ci		dev_err(&adapter->netdev->dev, "could not configure RSS\n");
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	return rv;
9378c2ecf20Sopenharmony_ci}
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_civoid qlcnic_82xx_config_ipaddr(struct qlcnic_adapter *adapter,
9408c2ecf20Sopenharmony_ci			       __be32 ip, int cmd)
9418c2ecf20Sopenharmony_ci{
9428c2ecf20Sopenharmony_ci	struct qlcnic_nic_req req;
9438c2ecf20Sopenharmony_ci	struct qlcnic_ipaddr *ipa;
9448c2ecf20Sopenharmony_ci	u64 word;
9458c2ecf20Sopenharmony_ci	int rv;
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	memset(&req, 0, sizeof(struct qlcnic_nic_req));
9488c2ecf20Sopenharmony_ci	req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
9498c2ecf20Sopenharmony_ci
9508c2ecf20Sopenharmony_ci	word = QLCNIC_H2C_OPCODE_CONFIG_IPADDR | ((u64)adapter->portnum << 16);
9518c2ecf20Sopenharmony_ci	req.req_hdr = cpu_to_le64(word);
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci	req.words[0] = cpu_to_le64(cmd);
9548c2ecf20Sopenharmony_ci	ipa = (struct qlcnic_ipaddr *)&req.words[1];
9558c2ecf20Sopenharmony_ci	ipa->ipv4 = ip;
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci	rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
9588c2ecf20Sopenharmony_ci	if (rv != 0)
9598c2ecf20Sopenharmony_ci		dev_err(&adapter->netdev->dev,
9608c2ecf20Sopenharmony_ci				"could not notify %s IP 0x%x request\n",
9618c2ecf20Sopenharmony_ci				(cmd == QLCNIC_IP_UP) ? "Add" : "Remove", ip);
9628c2ecf20Sopenharmony_ci}
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ciint qlcnic_82xx_linkevent_request(struct qlcnic_adapter *adapter, int enable)
9658c2ecf20Sopenharmony_ci{
9668c2ecf20Sopenharmony_ci	struct qlcnic_nic_req req;
9678c2ecf20Sopenharmony_ci	u64 word;
9688c2ecf20Sopenharmony_ci	int rv;
9698c2ecf20Sopenharmony_ci	memset(&req, 0, sizeof(struct qlcnic_nic_req));
9708c2ecf20Sopenharmony_ci	req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci	word = QLCNIC_H2C_OPCODE_GET_LINKEVENT | ((u64)adapter->portnum << 16);
9738c2ecf20Sopenharmony_ci	req.req_hdr = cpu_to_le64(word);
9748c2ecf20Sopenharmony_ci	req.words[0] = cpu_to_le64(enable | (enable << 8));
9758c2ecf20Sopenharmony_ci	rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
9768c2ecf20Sopenharmony_ci	if (rv != 0)
9778c2ecf20Sopenharmony_ci		dev_err(&adapter->netdev->dev,
9788c2ecf20Sopenharmony_ci				"could not configure link notification\n");
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci	return rv;
9818c2ecf20Sopenharmony_ci}
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_cistatic int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter)
9848c2ecf20Sopenharmony_ci{
9858c2ecf20Sopenharmony_ci	struct qlcnic_nic_req req;
9868c2ecf20Sopenharmony_ci	u64 word;
9878c2ecf20Sopenharmony_ci	int rv;
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci	if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))
9908c2ecf20Sopenharmony_ci		return 0;
9918c2ecf20Sopenharmony_ci
9928c2ecf20Sopenharmony_ci	memset(&req, 0, sizeof(struct qlcnic_nic_req));
9938c2ecf20Sopenharmony_ci	req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci	word = QLCNIC_H2C_OPCODE_LRO_REQUEST |
9968c2ecf20Sopenharmony_ci		((u64)adapter->portnum << 16) |
9978c2ecf20Sopenharmony_ci		((u64)QLCNIC_LRO_REQUEST_CLEANUP << 56) ;
9988c2ecf20Sopenharmony_ci
9998c2ecf20Sopenharmony_ci	req.req_hdr = cpu_to_le64(word);
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci	rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
10028c2ecf20Sopenharmony_ci	if (rv != 0)
10038c2ecf20Sopenharmony_ci		dev_err(&adapter->netdev->dev,
10048c2ecf20Sopenharmony_ci				 "could not cleanup lro flows\n");
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci	return rv;
10078c2ecf20Sopenharmony_ci}
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci/*
10108c2ecf20Sopenharmony_ci * qlcnic_change_mtu - Change the Maximum Transfer Unit
10118c2ecf20Sopenharmony_ci * @returns 0 on success, negative on failure
10128c2ecf20Sopenharmony_ci */
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ciint qlcnic_change_mtu(struct net_device *netdev, int mtu)
10158c2ecf20Sopenharmony_ci{
10168c2ecf20Sopenharmony_ci	struct qlcnic_adapter *adapter = netdev_priv(netdev);
10178c2ecf20Sopenharmony_ci	int rc = 0;
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci	rc = qlcnic_fw_cmd_set_mtu(adapter, mtu);
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci	if (!rc)
10228c2ecf20Sopenharmony_ci		netdev->mtu = mtu;
10238c2ecf20Sopenharmony_ci
10248c2ecf20Sopenharmony_ci	return rc;
10258c2ecf20Sopenharmony_ci}
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_cistatic netdev_features_t qlcnic_process_flags(struct qlcnic_adapter *adapter,
10288c2ecf20Sopenharmony_ci					      netdev_features_t features)
10298c2ecf20Sopenharmony_ci{
10308c2ecf20Sopenharmony_ci	u32 offload_flags = adapter->offload_flags;
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci	if (offload_flags & BIT_0) {
10338c2ecf20Sopenharmony_ci		features |= NETIF_F_RXCSUM | NETIF_F_IP_CSUM |
10348c2ecf20Sopenharmony_ci			    NETIF_F_IPV6_CSUM;
10358c2ecf20Sopenharmony_ci		adapter->rx_csum = 1;
10368c2ecf20Sopenharmony_ci		if (QLCNIC_IS_TSO_CAPABLE(adapter)) {
10378c2ecf20Sopenharmony_ci			if (!(offload_flags & BIT_1))
10388c2ecf20Sopenharmony_ci				features &= ~NETIF_F_TSO;
10398c2ecf20Sopenharmony_ci			else
10408c2ecf20Sopenharmony_ci				features |= NETIF_F_TSO;
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_ci			if (!(offload_flags & BIT_2))
10438c2ecf20Sopenharmony_ci				features &= ~NETIF_F_TSO6;
10448c2ecf20Sopenharmony_ci			else
10458c2ecf20Sopenharmony_ci				features |= NETIF_F_TSO6;
10468c2ecf20Sopenharmony_ci		}
10478c2ecf20Sopenharmony_ci	} else {
10488c2ecf20Sopenharmony_ci		features &= ~(NETIF_F_RXCSUM |
10498c2ecf20Sopenharmony_ci			      NETIF_F_IP_CSUM |
10508c2ecf20Sopenharmony_ci			      NETIF_F_IPV6_CSUM);
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci		if (QLCNIC_IS_TSO_CAPABLE(adapter))
10538c2ecf20Sopenharmony_ci			features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
10548c2ecf20Sopenharmony_ci		adapter->rx_csum = 0;
10558c2ecf20Sopenharmony_ci	}
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci	return features;
10588c2ecf20Sopenharmony_ci}
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_cinetdev_features_t qlcnic_fix_features(struct net_device *netdev,
10618c2ecf20Sopenharmony_ci	netdev_features_t features)
10628c2ecf20Sopenharmony_ci{
10638c2ecf20Sopenharmony_ci	struct qlcnic_adapter *adapter = netdev_priv(netdev);
10648c2ecf20Sopenharmony_ci	netdev_features_t changed;
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci	if (qlcnic_82xx_check(adapter) &&
10678c2ecf20Sopenharmony_ci	    (adapter->flags & QLCNIC_ESWITCH_ENABLED)) {
10688c2ecf20Sopenharmony_ci		if (adapter->flags & QLCNIC_APP_CHANGED_FLAGS) {
10698c2ecf20Sopenharmony_ci			features = qlcnic_process_flags(adapter, features);
10708c2ecf20Sopenharmony_ci		} else {
10718c2ecf20Sopenharmony_ci			changed = features ^ netdev->features;
10728c2ecf20Sopenharmony_ci			features ^= changed & (NETIF_F_RXCSUM |
10738c2ecf20Sopenharmony_ci					       NETIF_F_IP_CSUM |
10748c2ecf20Sopenharmony_ci					       NETIF_F_IPV6_CSUM |
10758c2ecf20Sopenharmony_ci					       NETIF_F_TSO |
10768c2ecf20Sopenharmony_ci					       NETIF_F_TSO6);
10778c2ecf20Sopenharmony_ci		}
10788c2ecf20Sopenharmony_ci	}
10798c2ecf20Sopenharmony_ci
10808c2ecf20Sopenharmony_ci	if (!(features & NETIF_F_RXCSUM))
10818c2ecf20Sopenharmony_ci		features &= ~NETIF_F_LRO;
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci	return features;
10848c2ecf20Sopenharmony_ci}
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ciint qlcnic_set_features(struct net_device *netdev, netdev_features_t features)
10888c2ecf20Sopenharmony_ci{
10898c2ecf20Sopenharmony_ci	struct qlcnic_adapter *adapter = netdev_priv(netdev);
10908c2ecf20Sopenharmony_ci	netdev_features_t changed = netdev->features ^ features;
10918c2ecf20Sopenharmony_ci	int hw_lro = (features & NETIF_F_LRO) ? QLCNIC_LRO_ENABLED : 0;
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci	if (!(changed & NETIF_F_LRO))
10948c2ecf20Sopenharmony_ci		return 0;
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_ci	netdev->features ^= NETIF_F_LRO;
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci	if (qlcnic_config_hw_lro(adapter, hw_lro))
10998c2ecf20Sopenharmony_ci		return -EIO;
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci	if (!hw_lro && qlcnic_82xx_check(adapter)) {
11028c2ecf20Sopenharmony_ci		if (qlcnic_send_lro_cleanup(adapter))
11038c2ecf20Sopenharmony_ci			return -EIO;
11048c2ecf20Sopenharmony_ci	}
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci	return 0;
11078c2ecf20Sopenharmony_ci}
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci/*
11108c2ecf20Sopenharmony_ci * Changes the CRB window to the specified window.
11118c2ecf20Sopenharmony_ci */
11128c2ecf20Sopenharmony_ci /* Returns < 0 if off is not valid,
11138c2ecf20Sopenharmony_ci *	 1 if window access is needed. 'off' is set to offset from
11148c2ecf20Sopenharmony_ci *	   CRB space in 128M pci map
11158c2ecf20Sopenharmony_ci *	 0 if no window access is needed. 'off' is set to 2M addr
11168c2ecf20Sopenharmony_ci * In: 'off' is offset from base in 128M pci map
11178c2ecf20Sopenharmony_ci */
11188c2ecf20Sopenharmony_cistatic int qlcnic_pci_get_crb_addr_2M(struct qlcnic_hardware_context *ahw,
11198c2ecf20Sopenharmony_ci				      ulong off, void __iomem **addr)
11208c2ecf20Sopenharmony_ci{
11218c2ecf20Sopenharmony_ci	const struct crb_128M_2M_sub_block_map *m;
11228c2ecf20Sopenharmony_ci
11238c2ecf20Sopenharmony_ci	if ((off >= QLCNIC_CRB_MAX) || (off < QLCNIC_PCI_CRBSPACE))
11248c2ecf20Sopenharmony_ci		return -EINVAL;
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci	off -= QLCNIC_PCI_CRBSPACE;
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci	/*
11298c2ecf20Sopenharmony_ci	 * Try direct map
11308c2ecf20Sopenharmony_ci	 */
11318c2ecf20Sopenharmony_ci	m = &crb_128M_2M_map[CRB_BLK(off)].sub_block[CRB_SUBBLK(off)];
11328c2ecf20Sopenharmony_ci
11338c2ecf20Sopenharmony_ci	if (m->valid && (m->start_128M <= off) && (m->end_128M > off)) {
11348c2ecf20Sopenharmony_ci		*addr = ahw->pci_base0 + m->start_2M +
11358c2ecf20Sopenharmony_ci			(off - m->start_128M);
11368c2ecf20Sopenharmony_ci		return 0;
11378c2ecf20Sopenharmony_ci	}
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci	/*
11408c2ecf20Sopenharmony_ci	 * Not in direct map, use crb window
11418c2ecf20Sopenharmony_ci	 */
11428c2ecf20Sopenharmony_ci	*addr = ahw->pci_base0 + CRB_INDIRECT_2M + (off & MASK(16));
11438c2ecf20Sopenharmony_ci	return 1;
11448c2ecf20Sopenharmony_ci}
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_ci/*
11478c2ecf20Sopenharmony_ci * In: 'off' is offset from CRB space in 128M pci map
11488c2ecf20Sopenharmony_ci * Out: 'off' is 2M pci map addr
11498c2ecf20Sopenharmony_ci * side effect: lock crb window
11508c2ecf20Sopenharmony_ci */
11518c2ecf20Sopenharmony_cistatic int
11528c2ecf20Sopenharmony_ciqlcnic_pci_set_crbwindow_2M(struct qlcnic_adapter *adapter, ulong off)
11538c2ecf20Sopenharmony_ci{
11548c2ecf20Sopenharmony_ci	u32 window;
11558c2ecf20Sopenharmony_ci	void __iomem *addr = adapter->ahw->pci_base0 + CRB_WINDOW_2M;
11568c2ecf20Sopenharmony_ci
11578c2ecf20Sopenharmony_ci	off -= QLCNIC_PCI_CRBSPACE;
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci	window = CRB_HI(off);
11608c2ecf20Sopenharmony_ci	if (window == 0) {
11618c2ecf20Sopenharmony_ci		dev_err(&adapter->pdev->dev, "Invalid offset 0x%lx\n", off);
11628c2ecf20Sopenharmony_ci		return -EIO;
11638c2ecf20Sopenharmony_ci	}
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci	writel(window, addr);
11668c2ecf20Sopenharmony_ci	if (readl(addr) != window) {
11678c2ecf20Sopenharmony_ci		if (printk_ratelimit())
11688c2ecf20Sopenharmony_ci			dev_warn(&adapter->pdev->dev,
11698c2ecf20Sopenharmony_ci				"failed to set CRB window to %d off 0x%lx\n",
11708c2ecf20Sopenharmony_ci				window, off);
11718c2ecf20Sopenharmony_ci		return -EIO;
11728c2ecf20Sopenharmony_ci	}
11738c2ecf20Sopenharmony_ci	return 0;
11748c2ecf20Sopenharmony_ci}
11758c2ecf20Sopenharmony_ci
11768c2ecf20Sopenharmony_ciint qlcnic_82xx_hw_write_wx_2M(struct qlcnic_adapter *adapter, ulong off,
11778c2ecf20Sopenharmony_ci			       u32 data)
11788c2ecf20Sopenharmony_ci{
11798c2ecf20Sopenharmony_ci	unsigned long flags;
11808c2ecf20Sopenharmony_ci	int rv;
11818c2ecf20Sopenharmony_ci	void __iomem *addr = NULL;
11828c2ecf20Sopenharmony_ci
11838c2ecf20Sopenharmony_ci	rv = qlcnic_pci_get_crb_addr_2M(adapter->ahw, off, &addr);
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_ci	if (rv == 0) {
11868c2ecf20Sopenharmony_ci		writel(data, addr);
11878c2ecf20Sopenharmony_ci		return 0;
11888c2ecf20Sopenharmony_ci	}
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci	if (rv > 0) {
11918c2ecf20Sopenharmony_ci		/* indirect access */
11928c2ecf20Sopenharmony_ci		write_lock_irqsave(&adapter->ahw->crb_lock, flags);
11938c2ecf20Sopenharmony_ci		crb_win_lock(adapter);
11948c2ecf20Sopenharmony_ci		rv = qlcnic_pci_set_crbwindow_2M(adapter, off);
11958c2ecf20Sopenharmony_ci		if (!rv)
11968c2ecf20Sopenharmony_ci			writel(data, addr);
11978c2ecf20Sopenharmony_ci		crb_win_unlock(adapter);
11988c2ecf20Sopenharmony_ci		write_unlock_irqrestore(&adapter->ahw->crb_lock, flags);
11998c2ecf20Sopenharmony_ci		return rv;
12008c2ecf20Sopenharmony_ci	}
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_ci	dev_err(&adapter->pdev->dev,
12038c2ecf20Sopenharmony_ci			"%s: invalid offset: 0x%016lx\n", __func__, off);
12048c2ecf20Sopenharmony_ci	dump_stack();
12058c2ecf20Sopenharmony_ci	return -EIO;
12068c2ecf20Sopenharmony_ci}
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ciint qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off,
12098c2ecf20Sopenharmony_ci			      int *err)
12108c2ecf20Sopenharmony_ci{
12118c2ecf20Sopenharmony_ci	unsigned long flags;
12128c2ecf20Sopenharmony_ci	int rv;
12138c2ecf20Sopenharmony_ci	u32 data = -1;
12148c2ecf20Sopenharmony_ci	void __iomem *addr = NULL;
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci	rv = qlcnic_pci_get_crb_addr_2M(adapter->ahw, off, &addr);
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci	if (rv == 0)
12198c2ecf20Sopenharmony_ci		return readl(addr);
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci	if (rv > 0) {
12228c2ecf20Sopenharmony_ci		/* indirect access */
12238c2ecf20Sopenharmony_ci		write_lock_irqsave(&adapter->ahw->crb_lock, flags);
12248c2ecf20Sopenharmony_ci		crb_win_lock(adapter);
12258c2ecf20Sopenharmony_ci		if (!qlcnic_pci_set_crbwindow_2M(adapter, off))
12268c2ecf20Sopenharmony_ci			data = readl(addr);
12278c2ecf20Sopenharmony_ci		crb_win_unlock(adapter);
12288c2ecf20Sopenharmony_ci		write_unlock_irqrestore(&adapter->ahw->crb_lock, flags);
12298c2ecf20Sopenharmony_ci		return data;
12308c2ecf20Sopenharmony_ci	}
12318c2ecf20Sopenharmony_ci
12328c2ecf20Sopenharmony_ci	dev_err(&adapter->pdev->dev,
12338c2ecf20Sopenharmony_ci			"%s: invalid offset: 0x%016lx\n", __func__, off);
12348c2ecf20Sopenharmony_ci	dump_stack();
12358c2ecf20Sopenharmony_ci	return -1;
12368c2ecf20Sopenharmony_ci}
12378c2ecf20Sopenharmony_ci
12388c2ecf20Sopenharmony_civoid __iomem *qlcnic_get_ioaddr(struct qlcnic_hardware_context *ahw,
12398c2ecf20Sopenharmony_ci				u32 offset)
12408c2ecf20Sopenharmony_ci{
12418c2ecf20Sopenharmony_ci	void __iomem *addr = NULL;
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci	WARN_ON(qlcnic_pci_get_crb_addr_2M(ahw, offset, &addr));
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci	return addr;
12468c2ecf20Sopenharmony_ci}
12478c2ecf20Sopenharmony_ci
12488c2ecf20Sopenharmony_cistatic int qlcnic_pci_mem_access_direct(struct qlcnic_adapter *adapter,
12498c2ecf20Sopenharmony_ci					u32 window, u64 off, u64 *data, int op)
12508c2ecf20Sopenharmony_ci{
12518c2ecf20Sopenharmony_ci	void __iomem *addr;
12528c2ecf20Sopenharmony_ci	u32 start;
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci	mutex_lock(&adapter->ahw->mem_lock);
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci	writel(window, adapter->ahw->ocm_win_crb);
12578c2ecf20Sopenharmony_ci	/* read back to flush */
12588c2ecf20Sopenharmony_ci	readl(adapter->ahw->ocm_win_crb);
12598c2ecf20Sopenharmony_ci	start = QLCNIC_PCI_OCM0_2M + off;
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci	addr = adapter->ahw->pci_base0 + start;
12628c2ecf20Sopenharmony_ci
12638c2ecf20Sopenharmony_ci	if (op == 0)	/* read */
12648c2ecf20Sopenharmony_ci		*data = readq(addr);
12658c2ecf20Sopenharmony_ci	else		/* write */
12668c2ecf20Sopenharmony_ci		writeq(*data, addr);
12678c2ecf20Sopenharmony_ci
12688c2ecf20Sopenharmony_ci	/* Set window to 0 */
12698c2ecf20Sopenharmony_ci	writel(0, adapter->ahw->ocm_win_crb);
12708c2ecf20Sopenharmony_ci	readl(adapter->ahw->ocm_win_crb);
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_ci	mutex_unlock(&adapter->ahw->mem_lock);
12738c2ecf20Sopenharmony_ci	return 0;
12748c2ecf20Sopenharmony_ci}
12758c2ecf20Sopenharmony_ci
12768c2ecf20Sopenharmony_cistatic void
12778c2ecf20Sopenharmony_ciqlcnic_pci_camqm_read_2M(struct qlcnic_adapter *adapter, u64 off, u64 *data)
12788c2ecf20Sopenharmony_ci{
12798c2ecf20Sopenharmony_ci	void __iomem *addr = adapter->ahw->pci_base0 +
12808c2ecf20Sopenharmony_ci		QLCNIC_PCI_CAMQM_2M_BASE + (off - QLCNIC_PCI_CAMQM);
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_ci	mutex_lock(&adapter->ahw->mem_lock);
12838c2ecf20Sopenharmony_ci	*data = readq(addr);
12848c2ecf20Sopenharmony_ci	mutex_unlock(&adapter->ahw->mem_lock);
12858c2ecf20Sopenharmony_ci}
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_cistatic void
12888c2ecf20Sopenharmony_ciqlcnic_pci_camqm_write_2M(struct qlcnic_adapter *adapter, u64 off, u64 data)
12898c2ecf20Sopenharmony_ci{
12908c2ecf20Sopenharmony_ci	void __iomem *addr = adapter->ahw->pci_base0 +
12918c2ecf20Sopenharmony_ci		QLCNIC_PCI_CAMQM_2M_BASE + (off - QLCNIC_PCI_CAMQM);
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci	mutex_lock(&adapter->ahw->mem_lock);
12948c2ecf20Sopenharmony_ci	writeq(data, addr);
12958c2ecf20Sopenharmony_ci	mutex_unlock(&adapter->ahw->mem_lock);
12968c2ecf20Sopenharmony_ci}
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci/* Set MS memory control data for different adapters */
13018c2ecf20Sopenharmony_cistatic void qlcnic_set_ms_controls(struct qlcnic_adapter *adapter, u64 off,
13028c2ecf20Sopenharmony_ci				   struct qlcnic_ms_reg_ctrl *ms)
13038c2ecf20Sopenharmony_ci{
13048c2ecf20Sopenharmony_ci	ms->control = QLCNIC_MS_CTRL;
13058c2ecf20Sopenharmony_ci	ms->low = QLCNIC_MS_ADDR_LO;
13068c2ecf20Sopenharmony_ci	ms->hi = QLCNIC_MS_ADDR_HI;
13078c2ecf20Sopenharmony_ci	if (off & 0xf) {
13088c2ecf20Sopenharmony_ci		ms->wd[0] = QLCNIC_MS_WRTDATA_LO;
13098c2ecf20Sopenharmony_ci		ms->rd[0] = QLCNIC_MS_RDDATA_LO;
13108c2ecf20Sopenharmony_ci		ms->wd[1] = QLCNIC_MS_WRTDATA_HI;
13118c2ecf20Sopenharmony_ci		ms->rd[1] = QLCNIC_MS_RDDATA_HI;
13128c2ecf20Sopenharmony_ci		ms->wd[2] = QLCNIC_MS_WRTDATA_ULO;
13138c2ecf20Sopenharmony_ci		ms->wd[3] = QLCNIC_MS_WRTDATA_UHI;
13148c2ecf20Sopenharmony_ci		ms->rd[2] = QLCNIC_MS_RDDATA_ULO;
13158c2ecf20Sopenharmony_ci		ms->rd[3] = QLCNIC_MS_RDDATA_UHI;
13168c2ecf20Sopenharmony_ci	} else {
13178c2ecf20Sopenharmony_ci		ms->wd[0] = QLCNIC_MS_WRTDATA_ULO;
13188c2ecf20Sopenharmony_ci		ms->rd[0] = QLCNIC_MS_RDDATA_ULO;
13198c2ecf20Sopenharmony_ci		ms->wd[1] = QLCNIC_MS_WRTDATA_UHI;
13208c2ecf20Sopenharmony_ci		ms->rd[1] = QLCNIC_MS_RDDATA_UHI;
13218c2ecf20Sopenharmony_ci		ms->wd[2] = QLCNIC_MS_WRTDATA_LO;
13228c2ecf20Sopenharmony_ci		ms->wd[3] = QLCNIC_MS_WRTDATA_HI;
13238c2ecf20Sopenharmony_ci		ms->rd[2] = QLCNIC_MS_RDDATA_LO;
13248c2ecf20Sopenharmony_ci		ms->rd[3] = QLCNIC_MS_RDDATA_HI;
13258c2ecf20Sopenharmony_ci	}
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci	ms->ocm_window = OCM_WIN_P3P(off);
13288c2ecf20Sopenharmony_ci	ms->off = GET_MEM_OFFS_2M(off);
13298c2ecf20Sopenharmony_ci}
13308c2ecf20Sopenharmony_ci
13318c2ecf20Sopenharmony_ciint qlcnic_pci_mem_write_2M(struct qlcnic_adapter *adapter, u64 off, u64 data)
13328c2ecf20Sopenharmony_ci{
13338c2ecf20Sopenharmony_ci	int j, ret = 0;
13348c2ecf20Sopenharmony_ci	u32 temp, off8;
13358c2ecf20Sopenharmony_ci	struct qlcnic_ms_reg_ctrl ms;
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_ci	/* Only 64-bit aligned access */
13388c2ecf20Sopenharmony_ci	if (off & 7)
13398c2ecf20Sopenharmony_ci		return -EIO;
13408c2ecf20Sopenharmony_ci
13418c2ecf20Sopenharmony_ci	memset(&ms, 0, sizeof(struct qlcnic_ms_reg_ctrl));
13428c2ecf20Sopenharmony_ci	if (!(ADDR_IN_RANGE(off, QLCNIC_ADDR_QDR_NET,
13438c2ecf20Sopenharmony_ci			    QLCNIC_ADDR_QDR_NET_MAX) ||
13448c2ecf20Sopenharmony_ci	      ADDR_IN_RANGE(off, QLCNIC_ADDR_DDR_NET,
13458c2ecf20Sopenharmony_ci			    QLCNIC_ADDR_DDR_NET_MAX)))
13468c2ecf20Sopenharmony_ci		return -EIO;
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci	qlcnic_set_ms_controls(adapter, off, &ms);
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_ci	if (ADDR_IN_RANGE(off, QLCNIC_ADDR_OCM0, QLCNIC_ADDR_OCM0_MAX))
13518c2ecf20Sopenharmony_ci		return qlcnic_pci_mem_access_direct(adapter, ms.ocm_window,
13528c2ecf20Sopenharmony_ci						    ms.off, &data, 1);
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_ci	off8 = off & ~0xf;
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci	mutex_lock(&adapter->ahw->mem_lock);
13578c2ecf20Sopenharmony_ci
13588c2ecf20Sopenharmony_ci	qlcnic_ind_wr(adapter, ms.low, off8);
13598c2ecf20Sopenharmony_ci	qlcnic_ind_wr(adapter, ms.hi, 0);
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_ci	qlcnic_ind_wr(adapter, ms.control, TA_CTL_ENABLE);
13628c2ecf20Sopenharmony_ci	qlcnic_ind_wr(adapter, ms.control, QLCNIC_TA_START_ENABLE);
13638c2ecf20Sopenharmony_ci
13648c2ecf20Sopenharmony_ci	for (j = 0; j < MAX_CTL_CHECK; j++) {
13658c2ecf20Sopenharmony_ci		temp = qlcnic_ind_rd(adapter, ms.control);
13668c2ecf20Sopenharmony_ci		if ((temp & TA_CTL_BUSY) == 0)
13678c2ecf20Sopenharmony_ci			break;
13688c2ecf20Sopenharmony_ci	}
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci	if (j >= MAX_CTL_CHECK) {
13718c2ecf20Sopenharmony_ci		ret = -EIO;
13728c2ecf20Sopenharmony_ci		goto done;
13738c2ecf20Sopenharmony_ci	}
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci	/* This is the modify part of read-modify-write */
13768c2ecf20Sopenharmony_ci	qlcnic_ind_wr(adapter, ms.wd[0], qlcnic_ind_rd(adapter, ms.rd[0]));
13778c2ecf20Sopenharmony_ci	qlcnic_ind_wr(adapter, ms.wd[1], qlcnic_ind_rd(adapter, ms.rd[1]));
13788c2ecf20Sopenharmony_ci	/* This is the write part of read-modify-write */
13798c2ecf20Sopenharmony_ci	qlcnic_ind_wr(adapter, ms.wd[2], data & 0xffffffff);
13808c2ecf20Sopenharmony_ci	qlcnic_ind_wr(adapter, ms.wd[3], (data >> 32) & 0xffffffff);
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_ci	qlcnic_ind_wr(adapter, ms.control, QLCNIC_TA_WRITE_ENABLE);
13838c2ecf20Sopenharmony_ci	qlcnic_ind_wr(adapter, ms.control, QLCNIC_TA_WRITE_START);
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_ci	for (j = 0; j < MAX_CTL_CHECK; j++) {
13868c2ecf20Sopenharmony_ci		temp = qlcnic_ind_rd(adapter, ms.control);
13878c2ecf20Sopenharmony_ci		if ((temp & TA_CTL_BUSY) == 0)
13888c2ecf20Sopenharmony_ci			break;
13898c2ecf20Sopenharmony_ci	}
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_ci	if (j >= MAX_CTL_CHECK) {
13928c2ecf20Sopenharmony_ci		if (printk_ratelimit())
13938c2ecf20Sopenharmony_ci			dev_err(&adapter->pdev->dev,
13948c2ecf20Sopenharmony_ci					"failed to write through agent\n");
13958c2ecf20Sopenharmony_ci		ret = -EIO;
13968c2ecf20Sopenharmony_ci	} else
13978c2ecf20Sopenharmony_ci		ret = 0;
13988c2ecf20Sopenharmony_ci
13998c2ecf20Sopenharmony_cidone:
14008c2ecf20Sopenharmony_ci	mutex_unlock(&adapter->ahw->mem_lock);
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci	return ret;
14038c2ecf20Sopenharmony_ci}
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ciint qlcnic_pci_mem_read_2M(struct qlcnic_adapter *adapter, u64 off, u64 *data)
14068c2ecf20Sopenharmony_ci{
14078c2ecf20Sopenharmony_ci	int j, ret;
14088c2ecf20Sopenharmony_ci	u32 temp, off8;
14098c2ecf20Sopenharmony_ci	u64 val;
14108c2ecf20Sopenharmony_ci	struct qlcnic_ms_reg_ctrl ms;
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci	/* Only 64-bit aligned access */
14138c2ecf20Sopenharmony_ci	if (off & 7)
14148c2ecf20Sopenharmony_ci		return -EIO;
14158c2ecf20Sopenharmony_ci	if (!(ADDR_IN_RANGE(off, QLCNIC_ADDR_QDR_NET,
14168c2ecf20Sopenharmony_ci			    QLCNIC_ADDR_QDR_NET_MAX) ||
14178c2ecf20Sopenharmony_ci	      ADDR_IN_RANGE(off, QLCNIC_ADDR_DDR_NET,
14188c2ecf20Sopenharmony_ci			    QLCNIC_ADDR_DDR_NET_MAX)))
14198c2ecf20Sopenharmony_ci		return -EIO;
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_ci	memset(&ms, 0, sizeof(struct qlcnic_ms_reg_ctrl));
14228c2ecf20Sopenharmony_ci	qlcnic_set_ms_controls(adapter, off, &ms);
14238c2ecf20Sopenharmony_ci
14248c2ecf20Sopenharmony_ci	if (ADDR_IN_RANGE(off, QLCNIC_ADDR_OCM0, QLCNIC_ADDR_OCM0_MAX))
14258c2ecf20Sopenharmony_ci		return qlcnic_pci_mem_access_direct(adapter, ms.ocm_window,
14268c2ecf20Sopenharmony_ci						    ms.off, data, 0);
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_ci	mutex_lock(&adapter->ahw->mem_lock);
14298c2ecf20Sopenharmony_ci
14308c2ecf20Sopenharmony_ci	off8 = off & ~0xf;
14318c2ecf20Sopenharmony_ci
14328c2ecf20Sopenharmony_ci	qlcnic_ind_wr(adapter, ms.low, off8);
14338c2ecf20Sopenharmony_ci	qlcnic_ind_wr(adapter, ms.hi, 0);
14348c2ecf20Sopenharmony_ci
14358c2ecf20Sopenharmony_ci	qlcnic_ind_wr(adapter, ms.control, TA_CTL_ENABLE);
14368c2ecf20Sopenharmony_ci	qlcnic_ind_wr(adapter, ms.control, QLCNIC_TA_START_ENABLE);
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ci	for (j = 0; j < MAX_CTL_CHECK; j++) {
14398c2ecf20Sopenharmony_ci		temp = qlcnic_ind_rd(adapter, ms.control);
14408c2ecf20Sopenharmony_ci		if ((temp & TA_CTL_BUSY) == 0)
14418c2ecf20Sopenharmony_ci			break;
14428c2ecf20Sopenharmony_ci	}
14438c2ecf20Sopenharmony_ci
14448c2ecf20Sopenharmony_ci	if (j >= MAX_CTL_CHECK) {
14458c2ecf20Sopenharmony_ci		if (printk_ratelimit())
14468c2ecf20Sopenharmony_ci			dev_err(&adapter->pdev->dev,
14478c2ecf20Sopenharmony_ci					"failed to read through agent\n");
14488c2ecf20Sopenharmony_ci		ret = -EIO;
14498c2ecf20Sopenharmony_ci	} else {
14508c2ecf20Sopenharmony_ci
14518c2ecf20Sopenharmony_ci		temp = qlcnic_ind_rd(adapter, ms.rd[3]);
14528c2ecf20Sopenharmony_ci		val = (u64)temp << 32;
14538c2ecf20Sopenharmony_ci		val |= qlcnic_ind_rd(adapter, ms.rd[2]);
14548c2ecf20Sopenharmony_ci		*data = val;
14558c2ecf20Sopenharmony_ci		ret = 0;
14568c2ecf20Sopenharmony_ci	}
14578c2ecf20Sopenharmony_ci
14588c2ecf20Sopenharmony_ci	mutex_unlock(&adapter->ahw->mem_lock);
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_ci	return ret;
14618c2ecf20Sopenharmony_ci}
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_ciint qlcnic_82xx_get_board_info(struct qlcnic_adapter *adapter)
14648c2ecf20Sopenharmony_ci{
14658c2ecf20Sopenharmony_ci	int offset, board_type, magic, err = 0;
14668c2ecf20Sopenharmony_ci	struct pci_dev *pdev = adapter->pdev;
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_ci	offset = QLCNIC_FW_MAGIC_OFFSET;
14698c2ecf20Sopenharmony_ci	if (qlcnic_rom_fast_read(adapter, offset, &magic))
14708c2ecf20Sopenharmony_ci		return -EIO;
14718c2ecf20Sopenharmony_ci
14728c2ecf20Sopenharmony_ci	if (magic != QLCNIC_BDINFO_MAGIC) {
14738c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "invalid board config, magic=%08x\n",
14748c2ecf20Sopenharmony_ci			magic);
14758c2ecf20Sopenharmony_ci		return -EIO;
14768c2ecf20Sopenharmony_ci	}
14778c2ecf20Sopenharmony_ci
14788c2ecf20Sopenharmony_ci	offset = QLCNIC_BRDTYPE_OFFSET;
14798c2ecf20Sopenharmony_ci	if (qlcnic_rom_fast_read(adapter, offset, &board_type))
14808c2ecf20Sopenharmony_ci		return -EIO;
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_ci	adapter->ahw->board_type = board_type;
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_ci	if (board_type == QLCNIC_BRDTYPE_P3P_4_GB_MM) {
14858c2ecf20Sopenharmony_ci		u32 gpio = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_PAD_GPIO_I, &err);
14868c2ecf20Sopenharmony_ci		if (err == -EIO)
14878c2ecf20Sopenharmony_ci			return err;
14888c2ecf20Sopenharmony_ci		if ((gpio & 0x8000) == 0)
14898c2ecf20Sopenharmony_ci			board_type = QLCNIC_BRDTYPE_P3P_10G_TP;
14908c2ecf20Sopenharmony_ci	}
14918c2ecf20Sopenharmony_ci
14928c2ecf20Sopenharmony_ci	switch (board_type) {
14938c2ecf20Sopenharmony_ci	case QLCNIC_BRDTYPE_P3P_HMEZ:
14948c2ecf20Sopenharmony_ci	case QLCNIC_BRDTYPE_P3P_XG_LOM:
14958c2ecf20Sopenharmony_ci	case QLCNIC_BRDTYPE_P3P_10G_CX4:
14968c2ecf20Sopenharmony_ci	case QLCNIC_BRDTYPE_P3P_10G_CX4_LP:
14978c2ecf20Sopenharmony_ci	case QLCNIC_BRDTYPE_P3P_IMEZ:
14988c2ecf20Sopenharmony_ci	case QLCNIC_BRDTYPE_P3P_10G_SFP_PLUS:
14998c2ecf20Sopenharmony_ci	case QLCNIC_BRDTYPE_P3P_10G_SFP_CT:
15008c2ecf20Sopenharmony_ci	case QLCNIC_BRDTYPE_P3P_10G_SFP_QT:
15018c2ecf20Sopenharmony_ci	case QLCNIC_BRDTYPE_P3P_10G_XFP:
15028c2ecf20Sopenharmony_ci	case QLCNIC_BRDTYPE_P3P_10000_BASE_T:
15038c2ecf20Sopenharmony_ci		adapter->ahw->port_type = QLCNIC_XGBE;
15048c2ecf20Sopenharmony_ci		break;
15058c2ecf20Sopenharmony_ci	case QLCNIC_BRDTYPE_P3P_REF_QG:
15068c2ecf20Sopenharmony_ci	case QLCNIC_BRDTYPE_P3P_4_GB:
15078c2ecf20Sopenharmony_ci	case QLCNIC_BRDTYPE_P3P_4_GB_MM:
15088c2ecf20Sopenharmony_ci		adapter->ahw->port_type = QLCNIC_GBE;
15098c2ecf20Sopenharmony_ci		break;
15108c2ecf20Sopenharmony_ci	case QLCNIC_BRDTYPE_P3P_10G_TP:
15118c2ecf20Sopenharmony_ci		adapter->ahw->port_type = (adapter->portnum < 2) ?
15128c2ecf20Sopenharmony_ci			QLCNIC_XGBE : QLCNIC_GBE;
15138c2ecf20Sopenharmony_ci		break;
15148c2ecf20Sopenharmony_ci	default:
15158c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "unknown board type %x\n", board_type);
15168c2ecf20Sopenharmony_ci		adapter->ahw->port_type = QLCNIC_XGBE;
15178c2ecf20Sopenharmony_ci		break;
15188c2ecf20Sopenharmony_ci	}
15198c2ecf20Sopenharmony_ci
15208c2ecf20Sopenharmony_ci	return 0;
15218c2ecf20Sopenharmony_ci}
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_cistatic int
15248c2ecf20Sopenharmony_ciqlcnic_wol_supported(struct qlcnic_adapter *adapter)
15258c2ecf20Sopenharmony_ci{
15268c2ecf20Sopenharmony_ci	u32 wol_cfg;
15278c2ecf20Sopenharmony_ci	int err = 0;
15288c2ecf20Sopenharmony_ci
15298c2ecf20Sopenharmony_ci	wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG_NV, &err);
15308c2ecf20Sopenharmony_ci	if (wol_cfg & (1UL << adapter->portnum)) {
15318c2ecf20Sopenharmony_ci		wol_cfg = QLCRD32(adapter, QLCNIC_WOL_CONFIG, &err);
15328c2ecf20Sopenharmony_ci		if (err == -EIO)
15338c2ecf20Sopenharmony_ci			return err;
15348c2ecf20Sopenharmony_ci		if (wol_cfg & (1 << adapter->portnum))
15358c2ecf20Sopenharmony_ci			return 1;
15368c2ecf20Sopenharmony_ci	}
15378c2ecf20Sopenharmony_ci
15388c2ecf20Sopenharmony_ci	return 0;
15398c2ecf20Sopenharmony_ci}
15408c2ecf20Sopenharmony_ci
15418c2ecf20Sopenharmony_ciint qlcnic_82xx_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
15428c2ecf20Sopenharmony_ci{
15438c2ecf20Sopenharmony_ci	struct qlcnic_nic_req   req;
15448c2ecf20Sopenharmony_ci	int rv;
15458c2ecf20Sopenharmony_ci	u64 word;
15468c2ecf20Sopenharmony_ci
15478c2ecf20Sopenharmony_ci	memset(&req, 0, sizeof(struct qlcnic_nic_req));
15488c2ecf20Sopenharmony_ci	req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23);
15498c2ecf20Sopenharmony_ci
15508c2ecf20Sopenharmony_ci	word = QLCNIC_H2C_OPCODE_CONFIG_LED | ((u64)adapter->portnum << 16);
15518c2ecf20Sopenharmony_ci	req.req_hdr = cpu_to_le64(word);
15528c2ecf20Sopenharmony_ci
15538c2ecf20Sopenharmony_ci	req.words[0] = cpu_to_le64(((u64)rate << 32) | adapter->portnum);
15548c2ecf20Sopenharmony_ci	req.words[1] = cpu_to_le64(state);
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_ci	rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
15578c2ecf20Sopenharmony_ci	if (rv)
15588c2ecf20Sopenharmony_ci		dev_err(&adapter->pdev->dev, "LED configuration failed.\n");
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci	return rv;
15618c2ecf20Sopenharmony_ci}
15628c2ecf20Sopenharmony_ci
15638c2ecf20Sopenharmony_civoid qlcnic_82xx_get_beacon_state(struct qlcnic_adapter *adapter)
15648c2ecf20Sopenharmony_ci{
15658c2ecf20Sopenharmony_ci	struct qlcnic_hardware_context *ahw = adapter->ahw;
15668c2ecf20Sopenharmony_ci	struct qlcnic_cmd_args cmd;
15678c2ecf20Sopenharmony_ci	u8 beacon_state;
15688c2ecf20Sopenharmony_ci	int err = 0;
15698c2ecf20Sopenharmony_ci
15708c2ecf20Sopenharmony_ci	if (ahw->extra_capability[0] & QLCNIC_FW_CAPABILITY_2_BEACON) {
15718c2ecf20Sopenharmony_ci		err = qlcnic_alloc_mbx_args(&cmd, adapter,
15728c2ecf20Sopenharmony_ci					    QLCNIC_CMD_GET_LED_STATUS);
15738c2ecf20Sopenharmony_ci		if (!err) {
15748c2ecf20Sopenharmony_ci			err = qlcnic_issue_cmd(adapter, &cmd);
15758c2ecf20Sopenharmony_ci			if (err) {
15768c2ecf20Sopenharmony_ci				netdev_err(adapter->netdev,
15778c2ecf20Sopenharmony_ci					   "Failed to get current beacon state, err=%d\n",
15788c2ecf20Sopenharmony_ci					   err);
15798c2ecf20Sopenharmony_ci			} else {
15808c2ecf20Sopenharmony_ci				beacon_state = cmd.rsp.arg[1];
15818c2ecf20Sopenharmony_ci				if (beacon_state == QLCNIC_BEACON_DISABLE)
15828c2ecf20Sopenharmony_ci					ahw->beacon_state = QLCNIC_BEACON_OFF;
15838c2ecf20Sopenharmony_ci				else if (beacon_state == QLCNIC_BEACON_EANBLE)
15848c2ecf20Sopenharmony_ci					ahw->beacon_state = QLCNIC_BEACON_ON;
15858c2ecf20Sopenharmony_ci			}
15868c2ecf20Sopenharmony_ci		}
15878c2ecf20Sopenharmony_ci		qlcnic_free_mbx_args(&cmd);
15888c2ecf20Sopenharmony_ci	}
15898c2ecf20Sopenharmony_ci
15908c2ecf20Sopenharmony_ci	return;
15918c2ecf20Sopenharmony_ci}
15928c2ecf20Sopenharmony_ci
15938c2ecf20Sopenharmony_civoid qlcnic_82xx_get_func_no(struct qlcnic_adapter *adapter)
15948c2ecf20Sopenharmony_ci{
15958c2ecf20Sopenharmony_ci	void __iomem *msix_base_addr;
15968c2ecf20Sopenharmony_ci	u32 func;
15978c2ecf20Sopenharmony_ci	u32 msix_base;
15988c2ecf20Sopenharmony_ci
15998c2ecf20Sopenharmony_ci	pci_read_config_dword(adapter->pdev, QLCNIC_MSIX_TABLE_OFFSET, &func);
16008c2ecf20Sopenharmony_ci	msix_base_addr = adapter->ahw->pci_base0 + QLCNIC_MSIX_BASE;
16018c2ecf20Sopenharmony_ci	msix_base = readl(msix_base_addr);
16028c2ecf20Sopenharmony_ci	func = (func - msix_base) / QLCNIC_MSIX_TBL_PGSIZE;
16038c2ecf20Sopenharmony_ci	adapter->ahw->pci_func = func;
16048c2ecf20Sopenharmony_ci}
16058c2ecf20Sopenharmony_ci
16068c2ecf20Sopenharmony_civoid qlcnic_82xx_read_crb(struct qlcnic_adapter *adapter, char *buf,
16078c2ecf20Sopenharmony_ci			  loff_t offset, size_t size)
16088c2ecf20Sopenharmony_ci{
16098c2ecf20Sopenharmony_ci	int err = 0;
16108c2ecf20Sopenharmony_ci	u32 data;
16118c2ecf20Sopenharmony_ci	u64 qmdata;
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_ci	if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
16148c2ecf20Sopenharmony_ci		qlcnic_pci_camqm_read_2M(adapter, offset, &qmdata);
16158c2ecf20Sopenharmony_ci		memcpy(buf, &qmdata, size);
16168c2ecf20Sopenharmony_ci	} else {
16178c2ecf20Sopenharmony_ci		data = QLCRD32(adapter, offset, &err);
16188c2ecf20Sopenharmony_ci		memcpy(buf, &data, size);
16198c2ecf20Sopenharmony_ci	}
16208c2ecf20Sopenharmony_ci}
16218c2ecf20Sopenharmony_ci
16228c2ecf20Sopenharmony_civoid qlcnic_82xx_write_crb(struct qlcnic_adapter *adapter, char *buf,
16238c2ecf20Sopenharmony_ci			   loff_t offset, size_t size)
16248c2ecf20Sopenharmony_ci{
16258c2ecf20Sopenharmony_ci	u32 data;
16268c2ecf20Sopenharmony_ci	u64 qmdata;
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_ci	if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
16298c2ecf20Sopenharmony_ci		memcpy(&qmdata, buf, size);
16308c2ecf20Sopenharmony_ci		qlcnic_pci_camqm_write_2M(adapter, offset, qmdata);
16318c2ecf20Sopenharmony_ci	} else {
16328c2ecf20Sopenharmony_ci		memcpy(&data, buf, size);
16338c2ecf20Sopenharmony_ci		QLCWR32(adapter, offset, data);
16348c2ecf20Sopenharmony_ci	}
16358c2ecf20Sopenharmony_ci}
16368c2ecf20Sopenharmony_ci
16378c2ecf20Sopenharmony_ciint qlcnic_82xx_api_lock(struct qlcnic_adapter *adapter)
16388c2ecf20Sopenharmony_ci{
16398c2ecf20Sopenharmony_ci	return qlcnic_pcie_sem_lock(adapter, 5, 0);
16408c2ecf20Sopenharmony_ci}
16418c2ecf20Sopenharmony_ci
16428c2ecf20Sopenharmony_civoid qlcnic_82xx_api_unlock(struct qlcnic_adapter *adapter)
16438c2ecf20Sopenharmony_ci{
16448c2ecf20Sopenharmony_ci	qlcnic_pcie_sem_unlock(adapter, 5);
16458c2ecf20Sopenharmony_ci}
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_ciint qlcnic_82xx_shutdown(struct pci_dev *pdev)
16488c2ecf20Sopenharmony_ci{
16498c2ecf20Sopenharmony_ci	struct qlcnic_adapter *adapter = pci_get_drvdata(pdev);
16508c2ecf20Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
16518c2ecf20Sopenharmony_ci
16528c2ecf20Sopenharmony_ci	netif_device_detach(netdev);
16538c2ecf20Sopenharmony_ci
16548c2ecf20Sopenharmony_ci	qlcnic_cancel_idc_work(adapter);
16558c2ecf20Sopenharmony_ci
16568c2ecf20Sopenharmony_ci	if (netif_running(netdev))
16578c2ecf20Sopenharmony_ci		qlcnic_down(adapter, netdev);
16588c2ecf20Sopenharmony_ci
16598c2ecf20Sopenharmony_ci	qlcnic_clr_all_drv_state(adapter, 0);
16608c2ecf20Sopenharmony_ci
16618c2ecf20Sopenharmony_ci	clear_bit(__QLCNIC_RESETTING, &adapter->state);
16628c2ecf20Sopenharmony_ci
16638c2ecf20Sopenharmony_ci	if (qlcnic_wol_supported(adapter))
16648c2ecf20Sopenharmony_ci		device_wakeup_enable(&pdev->dev);
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci	return 0;
16678c2ecf20Sopenharmony_ci}
16688c2ecf20Sopenharmony_ci
16698c2ecf20Sopenharmony_ciint qlcnic_82xx_resume(struct qlcnic_adapter *adapter)
16708c2ecf20Sopenharmony_ci{
16718c2ecf20Sopenharmony_ci	struct net_device *netdev = adapter->netdev;
16728c2ecf20Sopenharmony_ci	int err;
16738c2ecf20Sopenharmony_ci
16748c2ecf20Sopenharmony_ci	err = qlcnic_start_firmware(adapter);
16758c2ecf20Sopenharmony_ci	if (err) {
16768c2ecf20Sopenharmony_ci		dev_err(&adapter->pdev->dev, "failed to start firmware\n");
16778c2ecf20Sopenharmony_ci		return err;
16788c2ecf20Sopenharmony_ci	}
16798c2ecf20Sopenharmony_ci
16808c2ecf20Sopenharmony_ci	if (netif_running(netdev)) {
16818c2ecf20Sopenharmony_ci		err = qlcnic_up(adapter, netdev);
16828c2ecf20Sopenharmony_ci		if (!err)
16838c2ecf20Sopenharmony_ci			qlcnic_restore_indev_addr(netdev, NETDEV_UP);
16848c2ecf20Sopenharmony_ci	}
16858c2ecf20Sopenharmony_ci
16868c2ecf20Sopenharmony_ci	netif_device_attach(netdev);
16878c2ecf20Sopenharmony_ci	qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
16888c2ecf20Sopenharmony_ci	return err;
16898c2ecf20Sopenharmony_ci}
1690