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