18c2ecf20Sopenharmony_ci/* bnx2.c: QLogic bnx2 network driver. 28c2ecf20Sopenharmony_ci * 38c2ecf20Sopenharmony_ci * Copyright (c) 2004-2014 Broadcom Corporation 48c2ecf20Sopenharmony_ci * Copyright (c) 2014-2015 QLogic Corporation 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 78c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by 88c2ecf20Sopenharmony_ci * the Free Software Foundation. 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Written by: Michael Chan (mchan@broadcom.com) 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/stringify.h> 198c2ecf20Sopenharmony_ci#include <linux/kernel.h> 208c2ecf20Sopenharmony_ci#include <linux/timer.h> 218c2ecf20Sopenharmony_ci#include <linux/errno.h> 228c2ecf20Sopenharmony_ci#include <linux/ioport.h> 238c2ecf20Sopenharmony_ci#include <linux/slab.h> 248c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 258c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 268c2ecf20Sopenharmony_ci#include <linux/pci.h> 278c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 288c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 298c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 308c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 318c2ecf20Sopenharmony_ci#include <linux/bitops.h> 328c2ecf20Sopenharmony_ci#include <asm/io.h> 338c2ecf20Sopenharmony_ci#include <asm/irq.h> 348c2ecf20Sopenharmony_ci#include <linux/delay.h> 358c2ecf20Sopenharmony_ci#include <asm/byteorder.h> 368c2ecf20Sopenharmony_ci#include <asm/page.h> 378c2ecf20Sopenharmony_ci#include <linux/time.h> 388c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 398c2ecf20Sopenharmony_ci#include <linux/mii.h> 408c2ecf20Sopenharmony_ci#include <linux/if.h> 418c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 428c2ecf20Sopenharmony_ci#include <net/ip.h> 438c2ecf20Sopenharmony_ci#include <net/tcp.h> 448c2ecf20Sopenharmony_ci#include <net/checksum.h> 458c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 468c2ecf20Sopenharmony_ci#include <linux/crc32.h> 478c2ecf20Sopenharmony_ci#include <linux/prefetch.h> 488c2ecf20Sopenharmony_ci#include <linux/cache.h> 498c2ecf20Sopenharmony_ci#include <linux/firmware.h> 508c2ecf20Sopenharmony_ci#include <linux/log2.h> 518c2ecf20Sopenharmony_ci#include <linux/aer.h> 528c2ecf20Sopenharmony_ci#include <linux/crash_dump.h> 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_CNIC) 558c2ecf20Sopenharmony_ci#define BCM_CNIC 1 568c2ecf20Sopenharmony_ci#include "cnic_if.h" 578c2ecf20Sopenharmony_ci#endif 588c2ecf20Sopenharmony_ci#include "bnx2.h" 598c2ecf20Sopenharmony_ci#include "bnx2_fw.h" 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci#define DRV_MODULE_NAME "bnx2" 628c2ecf20Sopenharmony_ci#define FW_MIPS_FILE_06 "bnx2/bnx2-mips-06-6.2.3.fw" 638c2ecf20Sopenharmony_ci#define FW_RV2P_FILE_06 "bnx2/bnx2-rv2p-06-6.0.15.fw" 648c2ecf20Sopenharmony_ci#define FW_MIPS_FILE_09 "bnx2/bnx2-mips-09-6.2.1b.fw" 658c2ecf20Sopenharmony_ci#define FW_RV2P_FILE_09_Ax "bnx2/bnx2-rv2p-09ax-6.0.17.fw" 668c2ecf20Sopenharmony_ci#define FW_RV2P_FILE_09 "bnx2/bnx2-rv2p-09-6.0.17.fw" 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci#define RUN_AT(x) (jiffies + (x)) 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/* Time in jiffies before concluding the transmitter is hung. */ 718c2ecf20Sopenharmony_ci#define TX_TIMEOUT (5*HZ) 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ciMODULE_AUTHOR("Michael Chan <mchan@broadcom.com>"); 748c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("QLogic BCM5706/5708/5709/5716 Driver"); 758c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 768c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FW_MIPS_FILE_06); 778c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FW_RV2P_FILE_06); 788c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FW_MIPS_FILE_09); 798c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FW_RV2P_FILE_09); 808c2ecf20Sopenharmony_ciMODULE_FIRMWARE(FW_RV2P_FILE_09_Ax); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic int disable_msi = 0; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cimodule_param(disable_msi, int, 0444); 858c2ecf20Sopenharmony_ciMODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)"); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_citypedef enum { 888c2ecf20Sopenharmony_ci BCM5706 = 0, 898c2ecf20Sopenharmony_ci NC370T, 908c2ecf20Sopenharmony_ci NC370I, 918c2ecf20Sopenharmony_ci BCM5706S, 928c2ecf20Sopenharmony_ci NC370F, 938c2ecf20Sopenharmony_ci BCM5708, 948c2ecf20Sopenharmony_ci BCM5708S, 958c2ecf20Sopenharmony_ci BCM5709, 968c2ecf20Sopenharmony_ci BCM5709S, 978c2ecf20Sopenharmony_ci BCM5716, 988c2ecf20Sopenharmony_ci BCM5716S, 998c2ecf20Sopenharmony_ci} board_t; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci/* indexed by board_t, above */ 1028c2ecf20Sopenharmony_cistatic struct { 1038c2ecf20Sopenharmony_ci char *name; 1048c2ecf20Sopenharmony_ci} board_info[] = { 1058c2ecf20Sopenharmony_ci { "Broadcom NetXtreme II BCM5706 1000Base-T" }, 1068c2ecf20Sopenharmony_ci { "HP NC370T Multifunction Gigabit Server Adapter" }, 1078c2ecf20Sopenharmony_ci { "HP NC370i Multifunction Gigabit Server Adapter" }, 1088c2ecf20Sopenharmony_ci { "Broadcom NetXtreme II BCM5706 1000Base-SX" }, 1098c2ecf20Sopenharmony_ci { "HP NC370F Multifunction Gigabit Server Adapter" }, 1108c2ecf20Sopenharmony_ci { "Broadcom NetXtreme II BCM5708 1000Base-T" }, 1118c2ecf20Sopenharmony_ci { "Broadcom NetXtreme II BCM5708 1000Base-SX" }, 1128c2ecf20Sopenharmony_ci { "Broadcom NetXtreme II BCM5709 1000Base-T" }, 1138c2ecf20Sopenharmony_ci { "Broadcom NetXtreme II BCM5709 1000Base-SX" }, 1148c2ecf20Sopenharmony_ci { "Broadcom NetXtreme II BCM5716 1000Base-T" }, 1158c2ecf20Sopenharmony_ci { "Broadcom NetXtreme II BCM5716 1000Base-SX" }, 1168c2ecf20Sopenharmony_ci }; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic const struct pci_device_id bnx2_pci_tbl[] = { 1198c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706, 1208c2ecf20Sopenharmony_ci PCI_VENDOR_ID_HP, 0x3101, 0, 0, NC370T }, 1218c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706, 1228c2ecf20Sopenharmony_ci PCI_VENDOR_ID_HP, 0x3106, 0, 0, NC370I }, 1238c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706, 1248c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706 }, 1258c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708, 1268c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708 }, 1278c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S, 1288c2ecf20Sopenharmony_ci PCI_VENDOR_ID_HP, 0x3102, 0, 0, NC370F }, 1298c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S, 1308c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706S }, 1318c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708S, 1328c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708S }, 1338c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709, 1348c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709 }, 1358c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709S, 1368c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709S }, 1378c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_BROADCOM, 0x163b, 1388c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5716 }, 1398c2ecf20Sopenharmony_ci { PCI_VENDOR_ID_BROADCOM, 0x163c, 1408c2ecf20Sopenharmony_ci PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5716S }, 1418c2ecf20Sopenharmony_ci { 0, } 1428c2ecf20Sopenharmony_ci}; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic const struct flash_spec flash_table[] = 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci#define BUFFERED_FLAGS (BNX2_NV_BUFFERED | BNX2_NV_TRANSLATE) 1478c2ecf20Sopenharmony_ci#define NONBUFFERED_FLAGS (BNX2_NV_WREN) 1488c2ecf20Sopenharmony_ci /* Slow EEPROM */ 1498c2ecf20Sopenharmony_ci {0x00000000, 0x40830380, 0x009f0081, 0xa184a053, 0xaf000400, 1508c2ecf20Sopenharmony_ci BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE, 1518c2ecf20Sopenharmony_ci SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE, 1528c2ecf20Sopenharmony_ci "EEPROM - slow"}, 1538c2ecf20Sopenharmony_ci /* Expansion entry 0001 */ 1548c2ecf20Sopenharmony_ci {0x08000002, 0x4b808201, 0x00050081, 0x03840253, 0xaf020406, 1558c2ecf20Sopenharmony_ci NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, 1568c2ecf20Sopenharmony_ci SAIFUN_FLASH_BYTE_ADDR_MASK, 0, 1578c2ecf20Sopenharmony_ci "Entry 0001"}, 1588c2ecf20Sopenharmony_ci /* Saifun SA25F010 (non-buffered flash) */ 1598c2ecf20Sopenharmony_ci /* strap, cfg1, & write1 need updates */ 1608c2ecf20Sopenharmony_ci {0x04000001, 0x47808201, 0x00050081, 0x03840253, 0xaf020406, 1618c2ecf20Sopenharmony_ci NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, 1628c2ecf20Sopenharmony_ci SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*2, 1638c2ecf20Sopenharmony_ci "Non-buffered flash (128kB)"}, 1648c2ecf20Sopenharmony_ci /* Saifun SA25F020 (non-buffered flash) */ 1658c2ecf20Sopenharmony_ci /* strap, cfg1, & write1 need updates */ 1668c2ecf20Sopenharmony_ci {0x0c000003, 0x4f808201, 0x00050081, 0x03840253, 0xaf020406, 1678c2ecf20Sopenharmony_ci NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, 1688c2ecf20Sopenharmony_ci SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*4, 1698c2ecf20Sopenharmony_ci "Non-buffered flash (256kB)"}, 1708c2ecf20Sopenharmony_ci /* Expansion entry 0100 */ 1718c2ecf20Sopenharmony_ci {0x11000000, 0x53808201, 0x00050081, 0x03840253, 0xaf020406, 1728c2ecf20Sopenharmony_ci NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, 1738c2ecf20Sopenharmony_ci SAIFUN_FLASH_BYTE_ADDR_MASK, 0, 1748c2ecf20Sopenharmony_ci "Entry 0100"}, 1758c2ecf20Sopenharmony_ci /* Entry 0101: ST M45PE10 (non-buffered flash, TetonII B0) */ 1768c2ecf20Sopenharmony_ci {0x19000002, 0x5b808201, 0x000500db, 0x03840253, 0xaf020406, 1778c2ecf20Sopenharmony_ci NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE, 1788c2ecf20Sopenharmony_ci ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*2, 1798c2ecf20Sopenharmony_ci "Entry 0101: ST M45PE10 (128kB non-bufferred)"}, 1808c2ecf20Sopenharmony_ci /* Entry 0110: ST M45PE20 (non-buffered flash)*/ 1818c2ecf20Sopenharmony_ci {0x15000001, 0x57808201, 0x000500db, 0x03840253, 0xaf020406, 1828c2ecf20Sopenharmony_ci NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE, 1838c2ecf20Sopenharmony_ci ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*4, 1848c2ecf20Sopenharmony_ci "Entry 0110: ST M45PE20 (256kB non-bufferred)"}, 1858c2ecf20Sopenharmony_ci /* Saifun SA25F005 (non-buffered flash) */ 1868c2ecf20Sopenharmony_ci /* strap, cfg1, & write1 need updates */ 1878c2ecf20Sopenharmony_ci {0x1d000003, 0x5f808201, 0x00050081, 0x03840253, 0xaf020406, 1888c2ecf20Sopenharmony_ci NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, 1898c2ecf20Sopenharmony_ci SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE, 1908c2ecf20Sopenharmony_ci "Non-buffered flash (64kB)"}, 1918c2ecf20Sopenharmony_ci /* Fast EEPROM */ 1928c2ecf20Sopenharmony_ci {0x22000000, 0x62808380, 0x009f0081, 0xa184a053, 0xaf000400, 1938c2ecf20Sopenharmony_ci BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE, 1948c2ecf20Sopenharmony_ci SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE, 1958c2ecf20Sopenharmony_ci "EEPROM - fast"}, 1968c2ecf20Sopenharmony_ci /* Expansion entry 1001 */ 1978c2ecf20Sopenharmony_ci {0x2a000002, 0x6b808201, 0x00050081, 0x03840253, 0xaf020406, 1988c2ecf20Sopenharmony_ci NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, 1998c2ecf20Sopenharmony_ci SAIFUN_FLASH_BYTE_ADDR_MASK, 0, 2008c2ecf20Sopenharmony_ci "Entry 1001"}, 2018c2ecf20Sopenharmony_ci /* Expansion entry 1010 */ 2028c2ecf20Sopenharmony_ci {0x26000001, 0x67808201, 0x00050081, 0x03840253, 0xaf020406, 2038c2ecf20Sopenharmony_ci NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, 2048c2ecf20Sopenharmony_ci SAIFUN_FLASH_BYTE_ADDR_MASK, 0, 2058c2ecf20Sopenharmony_ci "Entry 1010"}, 2068c2ecf20Sopenharmony_ci /* ATMEL AT45DB011B (buffered flash) */ 2078c2ecf20Sopenharmony_ci {0x2e000003, 0x6e808273, 0x00570081, 0x68848353, 0xaf000400, 2088c2ecf20Sopenharmony_ci BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE, 2098c2ecf20Sopenharmony_ci BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE, 2108c2ecf20Sopenharmony_ci "Buffered flash (128kB)"}, 2118c2ecf20Sopenharmony_ci /* Expansion entry 1100 */ 2128c2ecf20Sopenharmony_ci {0x33000000, 0x73808201, 0x00050081, 0x03840253, 0xaf020406, 2138c2ecf20Sopenharmony_ci NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, 2148c2ecf20Sopenharmony_ci SAIFUN_FLASH_BYTE_ADDR_MASK, 0, 2158c2ecf20Sopenharmony_ci "Entry 1100"}, 2168c2ecf20Sopenharmony_ci /* Expansion entry 1101 */ 2178c2ecf20Sopenharmony_ci {0x3b000002, 0x7b808201, 0x00050081, 0x03840253, 0xaf020406, 2188c2ecf20Sopenharmony_ci NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE, 2198c2ecf20Sopenharmony_ci SAIFUN_FLASH_BYTE_ADDR_MASK, 0, 2208c2ecf20Sopenharmony_ci "Entry 1101"}, 2218c2ecf20Sopenharmony_ci /* Ateml Expansion entry 1110 */ 2228c2ecf20Sopenharmony_ci {0x37000001, 0x76808273, 0x00570081, 0x68848353, 0xaf000400, 2238c2ecf20Sopenharmony_ci BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE, 2248c2ecf20Sopenharmony_ci BUFFERED_FLASH_BYTE_ADDR_MASK, 0, 2258c2ecf20Sopenharmony_ci "Entry 1110 (Atmel)"}, 2268c2ecf20Sopenharmony_ci /* ATMEL AT45DB021B (buffered flash) */ 2278c2ecf20Sopenharmony_ci {0x3f000003, 0x7e808273, 0x00570081, 0x68848353, 0xaf000400, 2288c2ecf20Sopenharmony_ci BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE, 2298c2ecf20Sopenharmony_ci BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE*2, 2308c2ecf20Sopenharmony_ci "Buffered flash (256kB)"}, 2318c2ecf20Sopenharmony_ci}; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistatic const struct flash_spec flash_5709 = { 2348c2ecf20Sopenharmony_ci .flags = BNX2_NV_BUFFERED, 2358c2ecf20Sopenharmony_ci .page_bits = BCM5709_FLASH_PAGE_BITS, 2368c2ecf20Sopenharmony_ci .page_size = BCM5709_FLASH_PAGE_SIZE, 2378c2ecf20Sopenharmony_ci .addr_mask = BCM5709_FLASH_BYTE_ADDR_MASK, 2388c2ecf20Sopenharmony_ci .total_size = BUFFERED_FLASH_TOTAL_SIZE*2, 2398c2ecf20Sopenharmony_ci .name = "5709 Buffered flash (256kB)", 2408c2ecf20Sopenharmony_ci}; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, bnx2_pci_tbl); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistatic void bnx2_init_napi(struct bnx2 *bp); 2458c2ecf20Sopenharmony_cistatic void bnx2_del_napi(struct bnx2 *bp); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic inline u32 bnx2_tx_avail(struct bnx2 *bp, struct bnx2_tx_ring_info *txr) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci u32 diff; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci /* The ring uses 256 indices for 255 entries, one of them 2528c2ecf20Sopenharmony_ci * needs to be skipped. 2538c2ecf20Sopenharmony_ci */ 2548c2ecf20Sopenharmony_ci diff = READ_ONCE(txr->tx_prod) - READ_ONCE(txr->tx_cons); 2558c2ecf20Sopenharmony_ci if (unlikely(diff >= BNX2_TX_DESC_CNT)) { 2568c2ecf20Sopenharmony_ci diff &= 0xffff; 2578c2ecf20Sopenharmony_ci if (diff == BNX2_TX_DESC_CNT) 2588c2ecf20Sopenharmony_ci diff = BNX2_MAX_TX_DESC_CNT; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci return bp->tx_ring_size - diff; 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic u32 2648c2ecf20Sopenharmony_cibnx2_reg_rd_ind(struct bnx2 *bp, u32 offset) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci unsigned long flags; 2678c2ecf20Sopenharmony_ci u32 val; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci spin_lock_irqsave(&bp->indirect_lock, flags); 2708c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset); 2718c2ecf20Sopenharmony_ci val = BNX2_RD(bp, BNX2_PCICFG_REG_WINDOW); 2728c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bp->indirect_lock, flags); 2738c2ecf20Sopenharmony_ci return val; 2748c2ecf20Sopenharmony_ci} 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_cistatic void 2778c2ecf20Sopenharmony_cibnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci unsigned long flags; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci spin_lock_irqsave(&bp->indirect_lock, flags); 2828c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset); 2838c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW, val); 2848c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bp->indirect_lock, flags); 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic void 2888c2ecf20Sopenharmony_cibnx2_shmem_wr(struct bnx2 *bp, u32 offset, u32 val) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci bnx2_reg_wr_ind(bp, bp->shmem_base + offset, val); 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cistatic u32 2948c2ecf20Sopenharmony_cibnx2_shmem_rd(struct bnx2 *bp, u32 offset) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci return bnx2_reg_rd_ind(bp, bp->shmem_base + offset); 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_cistatic void 3008c2ecf20Sopenharmony_cibnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci unsigned long flags; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci offset += cid_addr; 3058c2ecf20Sopenharmony_ci spin_lock_irqsave(&bp->indirect_lock, flags); 3068c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5709) { 3078c2ecf20Sopenharmony_ci int i; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_CTX_CTX_DATA, val); 3108c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_CTX_CTX_CTRL, 3118c2ecf20Sopenharmony_ci offset | BNX2_CTX_CTX_CTRL_WRITE_REQ); 3128c2ecf20Sopenharmony_ci for (i = 0; i < 5; i++) { 3138c2ecf20Sopenharmony_ci val = BNX2_RD(bp, BNX2_CTX_CTX_CTRL); 3148c2ecf20Sopenharmony_ci if ((val & BNX2_CTX_CTX_CTRL_WRITE_REQ) == 0) 3158c2ecf20Sopenharmony_ci break; 3168c2ecf20Sopenharmony_ci udelay(5); 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci } else { 3198c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_CTX_DATA_ADR, offset); 3208c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_CTX_DATA, val); 3218c2ecf20Sopenharmony_ci } 3228c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&bp->indirect_lock, flags); 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci#ifdef BCM_CNIC 3268c2ecf20Sopenharmony_cistatic int 3278c2ecf20Sopenharmony_cibnx2_drv_ctl(struct net_device *dev, struct drv_ctl_info *info) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 3308c2ecf20Sopenharmony_ci struct drv_ctl_io *io = &info->data.io; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci switch (info->cmd) { 3338c2ecf20Sopenharmony_ci case DRV_CTL_IO_WR_CMD: 3348c2ecf20Sopenharmony_ci bnx2_reg_wr_ind(bp, io->offset, io->data); 3358c2ecf20Sopenharmony_ci break; 3368c2ecf20Sopenharmony_ci case DRV_CTL_IO_RD_CMD: 3378c2ecf20Sopenharmony_ci io->data = bnx2_reg_rd_ind(bp, io->offset); 3388c2ecf20Sopenharmony_ci break; 3398c2ecf20Sopenharmony_ci case DRV_CTL_CTX_WR_CMD: 3408c2ecf20Sopenharmony_ci bnx2_ctx_wr(bp, io->cid_addr, io->offset, io->data); 3418c2ecf20Sopenharmony_ci break; 3428c2ecf20Sopenharmony_ci default: 3438c2ecf20Sopenharmony_ci return -EINVAL; 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci return 0; 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_cistatic void bnx2_setup_cnic_irq_info(struct bnx2 *bp) 3498c2ecf20Sopenharmony_ci{ 3508c2ecf20Sopenharmony_ci struct cnic_eth_dev *cp = &bp->cnic_eth_dev; 3518c2ecf20Sopenharmony_ci struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; 3528c2ecf20Sopenharmony_ci int sb_id; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci if (bp->flags & BNX2_FLAG_USING_MSIX) { 3558c2ecf20Sopenharmony_ci cp->drv_state |= CNIC_DRV_STATE_USING_MSIX; 3568c2ecf20Sopenharmony_ci bnapi->cnic_present = 0; 3578c2ecf20Sopenharmony_ci sb_id = bp->irq_nvecs; 3588c2ecf20Sopenharmony_ci cp->irq_arr[0].irq_flags |= CNIC_IRQ_FL_MSIX; 3598c2ecf20Sopenharmony_ci } else { 3608c2ecf20Sopenharmony_ci cp->drv_state &= ~CNIC_DRV_STATE_USING_MSIX; 3618c2ecf20Sopenharmony_ci bnapi->cnic_tag = bnapi->last_status_idx; 3628c2ecf20Sopenharmony_ci bnapi->cnic_present = 1; 3638c2ecf20Sopenharmony_ci sb_id = 0; 3648c2ecf20Sopenharmony_ci cp->irq_arr[0].irq_flags &= ~CNIC_IRQ_FL_MSIX; 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci cp->irq_arr[0].vector = bp->irq_tbl[sb_id].vector; 3688c2ecf20Sopenharmony_ci cp->irq_arr[0].status_blk = (void *) 3698c2ecf20Sopenharmony_ci ((unsigned long) bnapi->status_blk.msi + 3708c2ecf20Sopenharmony_ci (BNX2_SBLK_MSIX_ALIGN_SIZE * sb_id)); 3718c2ecf20Sopenharmony_ci cp->irq_arr[0].status_blk_num = sb_id; 3728c2ecf20Sopenharmony_ci cp->num_irq = 1; 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistatic int bnx2_register_cnic(struct net_device *dev, struct cnic_ops *ops, 3768c2ecf20Sopenharmony_ci void *data) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 3798c2ecf20Sopenharmony_ci struct cnic_eth_dev *cp = &bp->cnic_eth_dev; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci if (!ops) 3828c2ecf20Sopenharmony_ci return -EINVAL; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (cp->drv_state & CNIC_DRV_STATE_REGD) 3858c2ecf20Sopenharmony_ci return -EBUSY; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci if (!bnx2_reg_rd_ind(bp, BNX2_FW_MAX_ISCSI_CONN)) 3888c2ecf20Sopenharmony_ci return -ENODEV; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci bp->cnic_data = data; 3918c2ecf20Sopenharmony_ci rcu_assign_pointer(bp->cnic_ops, ops); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci cp->num_irq = 0; 3948c2ecf20Sopenharmony_ci cp->drv_state = CNIC_DRV_STATE_REGD; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci bnx2_setup_cnic_irq_info(bp); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci return 0; 3998c2ecf20Sopenharmony_ci} 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_cistatic int bnx2_unregister_cnic(struct net_device *dev) 4028c2ecf20Sopenharmony_ci{ 4038c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 4048c2ecf20Sopenharmony_ci struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; 4058c2ecf20Sopenharmony_ci struct cnic_eth_dev *cp = &bp->cnic_eth_dev; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci mutex_lock(&bp->cnic_lock); 4088c2ecf20Sopenharmony_ci cp->drv_state = 0; 4098c2ecf20Sopenharmony_ci bnapi->cnic_present = 0; 4108c2ecf20Sopenharmony_ci RCU_INIT_POINTER(bp->cnic_ops, NULL); 4118c2ecf20Sopenharmony_ci mutex_unlock(&bp->cnic_lock); 4128c2ecf20Sopenharmony_ci synchronize_rcu(); 4138c2ecf20Sopenharmony_ci return 0; 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_cistatic struct cnic_eth_dev *bnx2_cnic_probe(struct net_device *dev) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 4198c2ecf20Sopenharmony_ci struct cnic_eth_dev *cp = &bp->cnic_eth_dev; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci if (!cp->max_iscsi_conn) 4228c2ecf20Sopenharmony_ci return NULL; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci cp->drv_owner = THIS_MODULE; 4258c2ecf20Sopenharmony_ci cp->chip_id = bp->chip_id; 4268c2ecf20Sopenharmony_ci cp->pdev = bp->pdev; 4278c2ecf20Sopenharmony_ci cp->io_base = bp->regview; 4288c2ecf20Sopenharmony_ci cp->drv_ctl = bnx2_drv_ctl; 4298c2ecf20Sopenharmony_ci cp->drv_register_cnic = bnx2_register_cnic; 4308c2ecf20Sopenharmony_ci cp->drv_unregister_cnic = bnx2_unregister_cnic; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci return cp; 4338c2ecf20Sopenharmony_ci} 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_cistatic void 4368c2ecf20Sopenharmony_cibnx2_cnic_stop(struct bnx2 *bp) 4378c2ecf20Sopenharmony_ci{ 4388c2ecf20Sopenharmony_ci struct cnic_ops *c_ops; 4398c2ecf20Sopenharmony_ci struct cnic_ctl_info info; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci mutex_lock(&bp->cnic_lock); 4428c2ecf20Sopenharmony_ci c_ops = rcu_dereference_protected(bp->cnic_ops, 4438c2ecf20Sopenharmony_ci lockdep_is_held(&bp->cnic_lock)); 4448c2ecf20Sopenharmony_ci if (c_ops) { 4458c2ecf20Sopenharmony_ci info.cmd = CNIC_CTL_STOP_CMD; 4468c2ecf20Sopenharmony_ci c_ops->cnic_ctl(bp->cnic_data, &info); 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci mutex_unlock(&bp->cnic_lock); 4498c2ecf20Sopenharmony_ci} 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_cistatic void 4528c2ecf20Sopenharmony_cibnx2_cnic_start(struct bnx2 *bp) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci struct cnic_ops *c_ops; 4558c2ecf20Sopenharmony_ci struct cnic_ctl_info info; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci mutex_lock(&bp->cnic_lock); 4588c2ecf20Sopenharmony_ci c_ops = rcu_dereference_protected(bp->cnic_ops, 4598c2ecf20Sopenharmony_ci lockdep_is_held(&bp->cnic_lock)); 4608c2ecf20Sopenharmony_ci if (c_ops) { 4618c2ecf20Sopenharmony_ci if (!(bp->flags & BNX2_FLAG_USING_MSIX)) { 4628c2ecf20Sopenharmony_ci struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci bnapi->cnic_tag = bnapi->last_status_idx; 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci info.cmd = CNIC_CTL_START_CMD; 4678c2ecf20Sopenharmony_ci c_ops->cnic_ctl(bp->cnic_data, &info); 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci mutex_unlock(&bp->cnic_lock); 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci#else 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_cistatic void 4758c2ecf20Sopenharmony_cibnx2_cnic_stop(struct bnx2 *bp) 4768c2ecf20Sopenharmony_ci{ 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistatic void 4808c2ecf20Sopenharmony_cibnx2_cnic_start(struct bnx2 *bp) 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci} 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci#endif 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_cistatic int 4878c2ecf20Sopenharmony_cibnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val) 4888c2ecf20Sopenharmony_ci{ 4898c2ecf20Sopenharmony_ci u32 val1; 4908c2ecf20Sopenharmony_ci int i, ret; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) { 4938c2ecf20Sopenharmony_ci val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_MODE); 4948c2ecf20Sopenharmony_ci val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_EMAC_MDIO_MODE, val1); 4978c2ecf20Sopenharmony_ci BNX2_RD(bp, BNX2_EMAC_MDIO_MODE); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci udelay(40); 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci val1 = (bp->phy_addr << 21) | (reg << 16) | 5038c2ecf20Sopenharmony_ci BNX2_EMAC_MDIO_COMM_COMMAND_READ | BNX2_EMAC_MDIO_COMM_DISEXT | 5048c2ecf20Sopenharmony_ci BNX2_EMAC_MDIO_COMM_START_BUSY; 5058c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_EMAC_MDIO_COMM, val1); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci for (i = 0; i < 50; i++) { 5088c2ecf20Sopenharmony_ci udelay(10); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_COMM); 5118c2ecf20Sopenharmony_ci if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) { 5128c2ecf20Sopenharmony_ci udelay(5); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_COMM); 5158c2ecf20Sopenharmony_ci val1 &= BNX2_EMAC_MDIO_COMM_DATA; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci break; 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY) { 5228c2ecf20Sopenharmony_ci *val = 0x0; 5238c2ecf20Sopenharmony_ci ret = -EBUSY; 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci else { 5268c2ecf20Sopenharmony_ci *val = val1; 5278c2ecf20Sopenharmony_ci ret = 0; 5288c2ecf20Sopenharmony_ci } 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) { 5318c2ecf20Sopenharmony_ci val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_MODE); 5328c2ecf20Sopenharmony_ci val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_EMAC_MDIO_MODE, val1); 5358c2ecf20Sopenharmony_ci BNX2_RD(bp, BNX2_EMAC_MDIO_MODE); 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci udelay(40); 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci return ret; 5418c2ecf20Sopenharmony_ci} 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_cistatic int 5448c2ecf20Sopenharmony_cibnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci u32 val1; 5478c2ecf20Sopenharmony_ci int i, ret; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) { 5508c2ecf20Sopenharmony_ci val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_MODE); 5518c2ecf20Sopenharmony_ci val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_EMAC_MDIO_MODE, val1); 5548c2ecf20Sopenharmony_ci BNX2_RD(bp, BNX2_EMAC_MDIO_MODE); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci udelay(40); 5578c2ecf20Sopenharmony_ci } 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci val1 = (bp->phy_addr << 21) | (reg << 16) | val | 5608c2ecf20Sopenharmony_ci BNX2_EMAC_MDIO_COMM_COMMAND_WRITE | 5618c2ecf20Sopenharmony_ci BNX2_EMAC_MDIO_COMM_START_BUSY | BNX2_EMAC_MDIO_COMM_DISEXT; 5628c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_EMAC_MDIO_COMM, val1); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci for (i = 0; i < 50; i++) { 5658c2ecf20Sopenharmony_ci udelay(10); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_COMM); 5688c2ecf20Sopenharmony_ci if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) { 5698c2ecf20Sopenharmony_ci udelay(5); 5708c2ecf20Sopenharmony_ci break; 5718c2ecf20Sopenharmony_ci } 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY) 5758c2ecf20Sopenharmony_ci ret = -EBUSY; 5768c2ecf20Sopenharmony_ci else 5778c2ecf20Sopenharmony_ci ret = 0; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_INT_MODE_AUTO_POLLING) { 5808c2ecf20Sopenharmony_ci val1 = BNX2_RD(bp, BNX2_EMAC_MDIO_MODE); 5818c2ecf20Sopenharmony_ci val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_EMAC_MDIO_MODE, val1); 5848c2ecf20Sopenharmony_ci BNX2_RD(bp, BNX2_EMAC_MDIO_MODE); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci udelay(40); 5878c2ecf20Sopenharmony_ci } 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci return ret; 5908c2ecf20Sopenharmony_ci} 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_cistatic void 5938c2ecf20Sopenharmony_cibnx2_disable_int(struct bnx2 *bp) 5948c2ecf20Sopenharmony_ci{ 5958c2ecf20Sopenharmony_ci int i; 5968c2ecf20Sopenharmony_ci struct bnx2_napi *bnapi; 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_ci for (i = 0; i < bp->irq_nvecs; i++) { 5998c2ecf20Sopenharmony_ci bnapi = &bp->bnx2_napi[i]; 6008c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num | 6018c2ecf20Sopenharmony_ci BNX2_PCICFG_INT_ACK_CMD_MASK_INT); 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci BNX2_RD(bp, BNX2_PCICFG_INT_ACK_CMD); 6048c2ecf20Sopenharmony_ci} 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_cistatic void 6078c2ecf20Sopenharmony_cibnx2_enable_int(struct bnx2 *bp) 6088c2ecf20Sopenharmony_ci{ 6098c2ecf20Sopenharmony_ci int i; 6108c2ecf20Sopenharmony_ci struct bnx2_napi *bnapi; 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci for (i = 0; i < bp->irq_nvecs; i++) { 6138c2ecf20Sopenharmony_ci bnapi = &bp->bnx2_napi[i]; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num | 6168c2ecf20Sopenharmony_ci BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | 6178c2ecf20Sopenharmony_ci BNX2_PCICFG_INT_ACK_CMD_MASK_INT | 6188c2ecf20Sopenharmony_ci bnapi->last_status_idx); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num | 6218c2ecf20Sopenharmony_ci BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | 6228c2ecf20Sopenharmony_ci bnapi->last_status_idx); 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW); 6258c2ecf20Sopenharmony_ci} 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_cistatic void 6288c2ecf20Sopenharmony_cibnx2_disable_int_sync(struct bnx2 *bp) 6298c2ecf20Sopenharmony_ci{ 6308c2ecf20Sopenharmony_ci int i; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci atomic_inc(&bp->intr_sem); 6338c2ecf20Sopenharmony_ci if (!netif_running(bp->dev)) 6348c2ecf20Sopenharmony_ci return; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci bnx2_disable_int(bp); 6378c2ecf20Sopenharmony_ci for (i = 0; i < bp->irq_nvecs; i++) 6388c2ecf20Sopenharmony_ci synchronize_irq(bp->irq_tbl[i].vector); 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_cistatic void 6428c2ecf20Sopenharmony_cibnx2_napi_disable(struct bnx2 *bp) 6438c2ecf20Sopenharmony_ci{ 6448c2ecf20Sopenharmony_ci int i; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci for (i = 0; i < bp->irq_nvecs; i++) 6478c2ecf20Sopenharmony_ci napi_disable(&bp->bnx2_napi[i].napi); 6488c2ecf20Sopenharmony_ci} 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_cistatic void 6518c2ecf20Sopenharmony_cibnx2_napi_enable(struct bnx2 *bp) 6528c2ecf20Sopenharmony_ci{ 6538c2ecf20Sopenharmony_ci int i; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci for (i = 0; i < bp->irq_nvecs; i++) 6568c2ecf20Sopenharmony_ci napi_enable(&bp->bnx2_napi[i].napi); 6578c2ecf20Sopenharmony_ci} 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_cistatic void 6608c2ecf20Sopenharmony_cibnx2_netif_stop(struct bnx2 *bp, bool stop_cnic) 6618c2ecf20Sopenharmony_ci{ 6628c2ecf20Sopenharmony_ci if (stop_cnic) 6638c2ecf20Sopenharmony_ci bnx2_cnic_stop(bp); 6648c2ecf20Sopenharmony_ci if (netif_running(bp->dev)) { 6658c2ecf20Sopenharmony_ci bnx2_napi_disable(bp); 6668c2ecf20Sopenharmony_ci netif_tx_disable(bp->dev); 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci bnx2_disable_int_sync(bp); 6698c2ecf20Sopenharmony_ci netif_carrier_off(bp->dev); /* prevent tx timeout */ 6708c2ecf20Sopenharmony_ci} 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_cistatic void 6738c2ecf20Sopenharmony_cibnx2_netif_start(struct bnx2 *bp, bool start_cnic) 6748c2ecf20Sopenharmony_ci{ 6758c2ecf20Sopenharmony_ci if (atomic_dec_and_test(&bp->intr_sem)) { 6768c2ecf20Sopenharmony_ci if (netif_running(bp->dev)) { 6778c2ecf20Sopenharmony_ci netif_tx_wake_all_queues(bp->dev); 6788c2ecf20Sopenharmony_ci spin_lock_bh(&bp->phy_lock); 6798c2ecf20Sopenharmony_ci if (bp->link_up) 6808c2ecf20Sopenharmony_ci netif_carrier_on(bp->dev); 6818c2ecf20Sopenharmony_ci spin_unlock_bh(&bp->phy_lock); 6828c2ecf20Sopenharmony_ci bnx2_napi_enable(bp); 6838c2ecf20Sopenharmony_ci bnx2_enable_int(bp); 6848c2ecf20Sopenharmony_ci if (start_cnic) 6858c2ecf20Sopenharmony_ci bnx2_cnic_start(bp); 6868c2ecf20Sopenharmony_ci } 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci} 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_cistatic void 6918c2ecf20Sopenharmony_cibnx2_free_tx_mem(struct bnx2 *bp) 6928c2ecf20Sopenharmony_ci{ 6938c2ecf20Sopenharmony_ci int i; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci for (i = 0; i < bp->num_tx_rings; i++) { 6968c2ecf20Sopenharmony_ci struct bnx2_napi *bnapi = &bp->bnx2_napi[i]; 6978c2ecf20Sopenharmony_ci struct bnx2_tx_ring_info *txr = &bnapi->tx_ring; 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci if (txr->tx_desc_ring) { 7008c2ecf20Sopenharmony_ci dma_free_coherent(&bp->pdev->dev, TXBD_RING_SIZE, 7018c2ecf20Sopenharmony_ci txr->tx_desc_ring, 7028c2ecf20Sopenharmony_ci txr->tx_desc_mapping); 7038c2ecf20Sopenharmony_ci txr->tx_desc_ring = NULL; 7048c2ecf20Sopenharmony_ci } 7058c2ecf20Sopenharmony_ci kfree(txr->tx_buf_ring); 7068c2ecf20Sopenharmony_ci txr->tx_buf_ring = NULL; 7078c2ecf20Sopenharmony_ci } 7088c2ecf20Sopenharmony_ci} 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_cistatic void 7118c2ecf20Sopenharmony_cibnx2_free_rx_mem(struct bnx2 *bp) 7128c2ecf20Sopenharmony_ci{ 7138c2ecf20Sopenharmony_ci int i; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci for (i = 0; i < bp->num_rx_rings; i++) { 7168c2ecf20Sopenharmony_ci struct bnx2_napi *bnapi = &bp->bnx2_napi[i]; 7178c2ecf20Sopenharmony_ci struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring; 7188c2ecf20Sopenharmony_ci int j; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci for (j = 0; j < bp->rx_max_ring; j++) { 7218c2ecf20Sopenharmony_ci if (rxr->rx_desc_ring[j]) 7228c2ecf20Sopenharmony_ci dma_free_coherent(&bp->pdev->dev, RXBD_RING_SIZE, 7238c2ecf20Sopenharmony_ci rxr->rx_desc_ring[j], 7248c2ecf20Sopenharmony_ci rxr->rx_desc_mapping[j]); 7258c2ecf20Sopenharmony_ci rxr->rx_desc_ring[j] = NULL; 7268c2ecf20Sopenharmony_ci } 7278c2ecf20Sopenharmony_ci vfree(rxr->rx_buf_ring); 7288c2ecf20Sopenharmony_ci rxr->rx_buf_ring = NULL; 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci for (j = 0; j < bp->rx_max_pg_ring; j++) { 7318c2ecf20Sopenharmony_ci if (rxr->rx_pg_desc_ring[j]) 7328c2ecf20Sopenharmony_ci dma_free_coherent(&bp->pdev->dev, RXBD_RING_SIZE, 7338c2ecf20Sopenharmony_ci rxr->rx_pg_desc_ring[j], 7348c2ecf20Sopenharmony_ci rxr->rx_pg_desc_mapping[j]); 7358c2ecf20Sopenharmony_ci rxr->rx_pg_desc_ring[j] = NULL; 7368c2ecf20Sopenharmony_ci } 7378c2ecf20Sopenharmony_ci vfree(rxr->rx_pg_ring); 7388c2ecf20Sopenharmony_ci rxr->rx_pg_ring = NULL; 7398c2ecf20Sopenharmony_ci } 7408c2ecf20Sopenharmony_ci} 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_cistatic int 7438c2ecf20Sopenharmony_cibnx2_alloc_tx_mem(struct bnx2 *bp) 7448c2ecf20Sopenharmony_ci{ 7458c2ecf20Sopenharmony_ci int i; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci for (i = 0; i < bp->num_tx_rings; i++) { 7488c2ecf20Sopenharmony_ci struct bnx2_napi *bnapi = &bp->bnx2_napi[i]; 7498c2ecf20Sopenharmony_ci struct bnx2_tx_ring_info *txr = &bnapi->tx_ring; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci txr->tx_buf_ring = kzalloc(SW_TXBD_RING_SIZE, GFP_KERNEL); 7528c2ecf20Sopenharmony_ci if (!txr->tx_buf_ring) 7538c2ecf20Sopenharmony_ci return -ENOMEM; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci txr->tx_desc_ring = 7568c2ecf20Sopenharmony_ci dma_alloc_coherent(&bp->pdev->dev, TXBD_RING_SIZE, 7578c2ecf20Sopenharmony_ci &txr->tx_desc_mapping, GFP_KERNEL); 7588c2ecf20Sopenharmony_ci if (!txr->tx_desc_ring) 7598c2ecf20Sopenharmony_ci return -ENOMEM; 7608c2ecf20Sopenharmony_ci } 7618c2ecf20Sopenharmony_ci return 0; 7628c2ecf20Sopenharmony_ci} 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_cistatic int 7658c2ecf20Sopenharmony_cibnx2_alloc_rx_mem(struct bnx2 *bp) 7668c2ecf20Sopenharmony_ci{ 7678c2ecf20Sopenharmony_ci int i; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci for (i = 0; i < bp->num_rx_rings; i++) { 7708c2ecf20Sopenharmony_ci struct bnx2_napi *bnapi = &bp->bnx2_napi[i]; 7718c2ecf20Sopenharmony_ci struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring; 7728c2ecf20Sopenharmony_ci int j; 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci rxr->rx_buf_ring = 7758c2ecf20Sopenharmony_ci vzalloc(array_size(SW_RXBD_RING_SIZE, bp->rx_max_ring)); 7768c2ecf20Sopenharmony_ci if (!rxr->rx_buf_ring) 7778c2ecf20Sopenharmony_ci return -ENOMEM; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci for (j = 0; j < bp->rx_max_ring; j++) { 7808c2ecf20Sopenharmony_ci rxr->rx_desc_ring[j] = 7818c2ecf20Sopenharmony_ci dma_alloc_coherent(&bp->pdev->dev, 7828c2ecf20Sopenharmony_ci RXBD_RING_SIZE, 7838c2ecf20Sopenharmony_ci &rxr->rx_desc_mapping[j], 7848c2ecf20Sopenharmony_ci GFP_KERNEL); 7858c2ecf20Sopenharmony_ci if (!rxr->rx_desc_ring[j]) 7868c2ecf20Sopenharmony_ci return -ENOMEM; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci } 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci if (bp->rx_pg_ring_size) { 7918c2ecf20Sopenharmony_ci rxr->rx_pg_ring = 7928c2ecf20Sopenharmony_ci vzalloc(array_size(SW_RXPG_RING_SIZE, 7938c2ecf20Sopenharmony_ci bp->rx_max_pg_ring)); 7948c2ecf20Sopenharmony_ci if (!rxr->rx_pg_ring) 7958c2ecf20Sopenharmony_ci return -ENOMEM; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci } 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci for (j = 0; j < bp->rx_max_pg_ring; j++) { 8008c2ecf20Sopenharmony_ci rxr->rx_pg_desc_ring[j] = 8018c2ecf20Sopenharmony_ci dma_alloc_coherent(&bp->pdev->dev, 8028c2ecf20Sopenharmony_ci RXBD_RING_SIZE, 8038c2ecf20Sopenharmony_ci &rxr->rx_pg_desc_mapping[j], 8048c2ecf20Sopenharmony_ci GFP_KERNEL); 8058c2ecf20Sopenharmony_ci if (!rxr->rx_pg_desc_ring[j]) 8068c2ecf20Sopenharmony_ci return -ENOMEM; 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci } 8098c2ecf20Sopenharmony_ci } 8108c2ecf20Sopenharmony_ci return 0; 8118c2ecf20Sopenharmony_ci} 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_cistatic void 8148c2ecf20Sopenharmony_cibnx2_free_stats_blk(struct net_device *dev) 8158c2ecf20Sopenharmony_ci{ 8168c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci if (bp->status_blk) { 8198c2ecf20Sopenharmony_ci dma_free_coherent(&bp->pdev->dev, bp->status_stats_size, 8208c2ecf20Sopenharmony_ci bp->status_blk, 8218c2ecf20Sopenharmony_ci bp->status_blk_mapping); 8228c2ecf20Sopenharmony_ci bp->status_blk = NULL; 8238c2ecf20Sopenharmony_ci bp->stats_blk = NULL; 8248c2ecf20Sopenharmony_ci } 8258c2ecf20Sopenharmony_ci} 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_cistatic int 8288c2ecf20Sopenharmony_cibnx2_alloc_stats_blk(struct net_device *dev) 8298c2ecf20Sopenharmony_ci{ 8308c2ecf20Sopenharmony_ci int status_blk_size; 8318c2ecf20Sopenharmony_ci void *status_blk; 8328c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci /* Combine status and statistics blocks into one allocation. */ 8358c2ecf20Sopenharmony_ci status_blk_size = L1_CACHE_ALIGN(sizeof(struct status_block)); 8368c2ecf20Sopenharmony_ci if (bp->flags & BNX2_FLAG_MSIX_CAP) 8378c2ecf20Sopenharmony_ci status_blk_size = L1_CACHE_ALIGN(BNX2_MAX_MSIX_HW_VEC * 8388c2ecf20Sopenharmony_ci BNX2_SBLK_MSIX_ALIGN_SIZE); 8398c2ecf20Sopenharmony_ci bp->status_stats_size = status_blk_size + 8408c2ecf20Sopenharmony_ci sizeof(struct statistics_block); 8418c2ecf20Sopenharmony_ci status_blk = dma_alloc_coherent(&bp->pdev->dev, bp->status_stats_size, 8428c2ecf20Sopenharmony_ci &bp->status_blk_mapping, GFP_KERNEL); 8438c2ecf20Sopenharmony_ci if (!status_blk) 8448c2ecf20Sopenharmony_ci return -ENOMEM; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci bp->status_blk = status_blk; 8478c2ecf20Sopenharmony_ci bp->stats_blk = status_blk + status_blk_size; 8488c2ecf20Sopenharmony_ci bp->stats_blk_mapping = bp->status_blk_mapping + status_blk_size; 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci return 0; 8518c2ecf20Sopenharmony_ci} 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_cistatic void 8548c2ecf20Sopenharmony_cibnx2_free_mem(struct bnx2 *bp) 8558c2ecf20Sopenharmony_ci{ 8568c2ecf20Sopenharmony_ci int i; 8578c2ecf20Sopenharmony_ci struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci bnx2_free_tx_mem(bp); 8608c2ecf20Sopenharmony_ci bnx2_free_rx_mem(bp); 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci for (i = 0; i < bp->ctx_pages; i++) { 8638c2ecf20Sopenharmony_ci if (bp->ctx_blk[i]) { 8648c2ecf20Sopenharmony_ci dma_free_coherent(&bp->pdev->dev, BNX2_PAGE_SIZE, 8658c2ecf20Sopenharmony_ci bp->ctx_blk[i], 8668c2ecf20Sopenharmony_ci bp->ctx_blk_mapping[i]); 8678c2ecf20Sopenharmony_ci bp->ctx_blk[i] = NULL; 8688c2ecf20Sopenharmony_ci } 8698c2ecf20Sopenharmony_ci } 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci if (bnapi->status_blk.msi) 8728c2ecf20Sopenharmony_ci bnapi->status_blk.msi = NULL; 8738c2ecf20Sopenharmony_ci} 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_cistatic int 8768c2ecf20Sopenharmony_cibnx2_alloc_mem(struct bnx2 *bp) 8778c2ecf20Sopenharmony_ci{ 8788c2ecf20Sopenharmony_ci int i, err; 8798c2ecf20Sopenharmony_ci struct bnx2_napi *bnapi; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci bnapi = &bp->bnx2_napi[0]; 8828c2ecf20Sopenharmony_ci bnapi->status_blk.msi = bp->status_blk; 8838c2ecf20Sopenharmony_ci bnapi->hw_tx_cons_ptr = 8848c2ecf20Sopenharmony_ci &bnapi->status_blk.msi->status_tx_quick_consumer_index0; 8858c2ecf20Sopenharmony_ci bnapi->hw_rx_cons_ptr = 8868c2ecf20Sopenharmony_ci &bnapi->status_blk.msi->status_rx_quick_consumer_index0; 8878c2ecf20Sopenharmony_ci if (bp->flags & BNX2_FLAG_MSIX_CAP) { 8888c2ecf20Sopenharmony_ci for (i = 1; i < bp->irq_nvecs; i++) { 8898c2ecf20Sopenharmony_ci struct status_block_msix *sblk; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci bnapi = &bp->bnx2_napi[i]; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci sblk = (bp->status_blk + BNX2_SBLK_MSIX_ALIGN_SIZE * i); 8948c2ecf20Sopenharmony_ci bnapi->status_blk.msix = sblk; 8958c2ecf20Sopenharmony_ci bnapi->hw_tx_cons_ptr = 8968c2ecf20Sopenharmony_ci &sblk->status_tx_quick_consumer_index; 8978c2ecf20Sopenharmony_ci bnapi->hw_rx_cons_ptr = 8988c2ecf20Sopenharmony_ci &sblk->status_rx_quick_consumer_index; 8998c2ecf20Sopenharmony_ci bnapi->int_num = i << 24; 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci } 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5709) { 9048c2ecf20Sopenharmony_ci bp->ctx_pages = 0x2000 / BNX2_PAGE_SIZE; 9058c2ecf20Sopenharmony_ci if (bp->ctx_pages == 0) 9068c2ecf20Sopenharmony_ci bp->ctx_pages = 1; 9078c2ecf20Sopenharmony_ci for (i = 0; i < bp->ctx_pages; i++) { 9088c2ecf20Sopenharmony_ci bp->ctx_blk[i] = dma_alloc_coherent(&bp->pdev->dev, 9098c2ecf20Sopenharmony_ci BNX2_PAGE_SIZE, 9108c2ecf20Sopenharmony_ci &bp->ctx_blk_mapping[i], 9118c2ecf20Sopenharmony_ci GFP_KERNEL); 9128c2ecf20Sopenharmony_ci if (!bp->ctx_blk[i]) 9138c2ecf20Sopenharmony_ci goto alloc_mem_err; 9148c2ecf20Sopenharmony_ci } 9158c2ecf20Sopenharmony_ci } 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci err = bnx2_alloc_rx_mem(bp); 9188c2ecf20Sopenharmony_ci if (err) 9198c2ecf20Sopenharmony_ci goto alloc_mem_err; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci err = bnx2_alloc_tx_mem(bp); 9228c2ecf20Sopenharmony_ci if (err) 9238c2ecf20Sopenharmony_ci goto alloc_mem_err; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci return 0; 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_cialloc_mem_err: 9288c2ecf20Sopenharmony_ci bnx2_free_mem(bp); 9298c2ecf20Sopenharmony_ci return -ENOMEM; 9308c2ecf20Sopenharmony_ci} 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_cistatic void 9338c2ecf20Sopenharmony_cibnx2_report_fw_link(struct bnx2 *bp) 9348c2ecf20Sopenharmony_ci{ 9358c2ecf20Sopenharmony_ci u32 fw_link_status = 0; 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) 9388c2ecf20Sopenharmony_ci return; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci if (bp->link_up) { 9418c2ecf20Sopenharmony_ci u32 bmsr; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci switch (bp->line_speed) { 9448c2ecf20Sopenharmony_ci case SPEED_10: 9458c2ecf20Sopenharmony_ci if (bp->duplex == DUPLEX_HALF) 9468c2ecf20Sopenharmony_ci fw_link_status = BNX2_LINK_STATUS_10HALF; 9478c2ecf20Sopenharmony_ci else 9488c2ecf20Sopenharmony_ci fw_link_status = BNX2_LINK_STATUS_10FULL; 9498c2ecf20Sopenharmony_ci break; 9508c2ecf20Sopenharmony_ci case SPEED_100: 9518c2ecf20Sopenharmony_ci if (bp->duplex == DUPLEX_HALF) 9528c2ecf20Sopenharmony_ci fw_link_status = BNX2_LINK_STATUS_100HALF; 9538c2ecf20Sopenharmony_ci else 9548c2ecf20Sopenharmony_ci fw_link_status = BNX2_LINK_STATUS_100FULL; 9558c2ecf20Sopenharmony_ci break; 9568c2ecf20Sopenharmony_ci case SPEED_1000: 9578c2ecf20Sopenharmony_ci if (bp->duplex == DUPLEX_HALF) 9588c2ecf20Sopenharmony_ci fw_link_status = BNX2_LINK_STATUS_1000HALF; 9598c2ecf20Sopenharmony_ci else 9608c2ecf20Sopenharmony_ci fw_link_status = BNX2_LINK_STATUS_1000FULL; 9618c2ecf20Sopenharmony_ci break; 9628c2ecf20Sopenharmony_ci case SPEED_2500: 9638c2ecf20Sopenharmony_ci if (bp->duplex == DUPLEX_HALF) 9648c2ecf20Sopenharmony_ci fw_link_status = BNX2_LINK_STATUS_2500HALF; 9658c2ecf20Sopenharmony_ci else 9668c2ecf20Sopenharmony_ci fw_link_status = BNX2_LINK_STATUS_2500FULL; 9678c2ecf20Sopenharmony_ci break; 9688c2ecf20Sopenharmony_ci } 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci fw_link_status |= BNX2_LINK_STATUS_LINK_UP; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci if (bp->autoneg) { 9738c2ecf20Sopenharmony_ci fw_link_status |= BNX2_LINK_STATUS_AN_ENABLED; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci bnx2_read_phy(bp, bp->mii_bmsr, &bmsr); 9768c2ecf20Sopenharmony_ci bnx2_read_phy(bp, bp->mii_bmsr, &bmsr); 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci if (!(bmsr & BMSR_ANEGCOMPLETE) || 9798c2ecf20Sopenharmony_ci bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT) 9808c2ecf20Sopenharmony_ci fw_link_status |= BNX2_LINK_STATUS_PARALLEL_DET; 9818c2ecf20Sopenharmony_ci else 9828c2ecf20Sopenharmony_ci fw_link_status |= BNX2_LINK_STATUS_AN_COMPLETE; 9838c2ecf20Sopenharmony_ci } 9848c2ecf20Sopenharmony_ci } 9858c2ecf20Sopenharmony_ci else 9868c2ecf20Sopenharmony_ci fw_link_status = BNX2_LINK_STATUS_LINK_DOWN; 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_ci bnx2_shmem_wr(bp, BNX2_LINK_STATUS, fw_link_status); 9898c2ecf20Sopenharmony_ci} 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_cistatic char * 9928c2ecf20Sopenharmony_cibnx2_xceiver_str(struct bnx2 *bp) 9938c2ecf20Sopenharmony_ci{ 9948c2ecf20Sopenharmony_ci return (bp->phy_port == PORT_FIBRE) ? "SerDes" : 9958c2ecf20Sopenharmony_ci ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) ? "Remote Copper" : 9968c2ecf20Sopenharmony_ci "Copper"); 9978c2ecf20Sopenharmony_ci} 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_cistatic void 10008c2ecf20Sopenharmony_cibnx2_report_link(struct bnx2 *bp) 10018c2ecf20Sopenharmony_ci{ 10028c2ecf20Sopenharmony_ci if (bp->link_up) { 10038c2ecf20Sopenharmony_ci netif_carrier_on(bp->dev); 10048c2ecf20Sopenharmony_ci netdev_info(bp->dev, "NIC %s Link is Up, %d Mbps %s duplex", 10058c2ecf20Sopenharmony_ci bnx2_xceiver_str(bp), 10068c2ecf20Sopenharmony_ci bp->line_speed, 10078c2ecf20Sopenharmony_ci bp->duplex == DUPLEX_FULL ? "full" : "half"); 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci if (bp->flow_ctrl) { 10108c2ecf20Sopenharmony_ci if (bp->flow_ctrl & FLOW_CTRL_RX) { 10118c2ecf20Sopenharmony_ci pr_cont(", receive "); 10128c2ecf20Sopenharmony_ci if (bp->flow_ctrl & FLOW_CTRL_TX) 10138c2ecf20Sopenharmony_ci pr_cont("& transmit "); 10148c2ecf20Sopenharmony_ci } 10158c2ecf20Sopenharmony_ci else { 10168c2ecf20Sopenharmony_ci pr_cont(", transmit "); 10178c2ecf20Sopenharmony_ci } 10188c2ecf20Sopenharmony_ci pr_cont("flow control ON"); 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci pr_cont("\n"); 10218c2ecf20Sopenharmony_ci } else { 10228c2ecf20Sopenharmony_ci netif_carrier_off(bp->dev); 10238c2ecf20Sopenharmony_ci netdev_err(bp->dev, "NIC %s Link is Down\n", 10248c2ecf20Sopenharmony_ci bnx2_xceiver_str(bp)); 10258c2ecf20Sopenharmony_ci } 10268c2ecf20Sopenharmony_ci 10278c2ecf20Sopenharmony_ci bnx2_report_fw_link(bp); 10288c2ecf20Sopenharmony_ci} 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_cistatic void 10318c2ecf20Sopenharmony_cibnx2_resolve_flow_ctrl(struct bnx2 *bp) 10328c2ecf20Sopenharmony_ci{ 10338c2ecf20Sopenharmony_ci u32 local_adv, remote_adv; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci bp->flow_ctrl = 0; 10368c2ecf20Sopenharmony_ci if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) != 10378c2ecf20Sopenharmony_ci (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) { 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci if (bp->duplex == DUPLEX_FULL) { 10408c2ecf20Sopenharmony_ci bp->flow_ctrl = bp->req_flow_ctrl; 10418c2ecf20Sopenharmony_ci } 10428c2ecf20Sopenharmony_ci return; 10438c2ecf20Sopenharmony_ci } 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci if (bp->duplex != DUPLEX_FULL) { 10468c2ecf20Sopenharmony_ci return; 10478c2ecf20Sopenharmony_ci } 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) && 10508c2ecf20Sopenharmony_ci (BNX2_CHIP(bp) == BNX2_CHIP_5708)) { 10518c2ecf20Sopenharmony_ci u32 val; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val); 10548c2ecf20Sopenharmony_ci if (val & BCM5708S_1000X_STAT1_TX_PAUSE) 10558c2ecf20Sopenharmony_ci bp->flow_ctrl |= FLOW_CTRL_TX; 10568c2ecf20Sopenharmony_ci if (val & BCM5708S_1000X_STAT1_RX_PAUSE) 10578c2ecf20Sopenharmony_ci bp->flow_ctrl |= FLOW_CTRL_RX; 10588c2ecf20Sopenharmony_ci return; 10598c2ecf20Sopenharmony_ci } 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci bnx2_read_phy(bp, bp->mii_adv, &local_adv); 10628c2ecf20Sopenharmony_ci bnx2_read_phy(bp, bp->mii_lpa, &remote_adv); 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) { 10658c2ecf20Sopenharmony_ci u32 new_local_adv = 0; 10668c2ecf20Sopenharmony_ci u32 new_remote_adv = 0; 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci if (local_adv & ADVERTISE_1000XPAUSE) 10698c2ecf20Sopenharmony_ci new_local_adv |= ADVERTISE_PAUSE_CAP; 10708c2ecf20Sopenharmony_ci if (local_adv & ADVERTISE_1000XPSE_ASYM) 10718c2ecf20Sopenharmony_ci new_local_adv |= ADVERTISE_PAUSE_ASYM; 10728c2ecf20Sopenharmony_ci if (remote_adv & ADVERTISE_1000XPAUSE) 10738c2ecf20Sopenharmony_ci new_remote_adv |= ADVERTISE_PAUSE_CAP; 10748c2ecf20Sopenharmony_ci if (remote_adv & ADVERTISE_1000XPSE_ASYM) 10758c2ecf20Sopenharmony_ci new_remote_adv |= ADVERTISE_PAUSE_ASYM; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci local_adv = new_local_adv; 10788c2ecf20Sopenharmony_ci remote_adv = new_remote_adv; 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci /* See Table 28B-3 of 802.3ab-1999 spec. */ 10828c2ecf20Sopenharmony_ci if (local_adv & ADVERTISE_PAUSE_CAP) { 10838c2ecf20Sopenharmony_ci if(local_adv & ADVERTISE_PAUSE_ASYM) { 10848c2ecf20Sopenharmony_ci if (remote_adv & ADVERTISE_PAUSE_CAP) { 10858c2ecf20Sopenharmony_ci bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX; 10868c2ecf20Sopenharmony_ci } 10878c2ecf20Sopenharmony_ci else if (remote_adv & ADVERTISE_PAUSE_ASYM) { 10888c2ecf20Sopenharmony_ci bp->flow_ctrl = FLOW_CTRL_RX; 10898c2ecf20Sopenharmony_ci } 10908c2ecf20Sopenharmony_ci } 10918c2ecf20Sopenharmony_ci else { 10928c2ecf20Sopenharmony_ci if (remote_adv & ADVERTISE_PAUSE_CAP) { 10938c2ecf20Sopenharmony_ci bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX; 10948c2ecf20Sopenharmony_ci } 10958c2ecf20Sopenharmony_ci } 10968c2ecf20Sopenharmony_ci } 10978c2ecf20Sopenharmony_ci else if (local_adv & ADVERTISE_PAUSE_ASYM) { 10988c2ecf20Sopenharmony_ci if ((remote_adv & ADVERTISE_PAUSE_CAP) && 10998c2ecf20Sopenharmony_ci (remote_adv & ADVERTISE_PAUSE_ASYM)) { 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci bp->flow_ctrl = FLOW_CTRL_TX; 11028c2ecf20Sopenharmony_ci } 11038c2ecf20Sopenharmony_ci } 11048c2ecf20Sopenharmony_ci} 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_cistatic int 11078c2ecf20Sopenharmony_cibnx2_5709s_linkup(struct bnx2 *bp) 11088c2ecf20Sopenharmony_ci{ 11098c2ecf20Sopenharmony_ci u32 val, speed; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci bp->link_up = 1; 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_GP_STATUS); 11148c2ecf20Sopenharmony_ci bnx2_read_phy(bp, MII_BNX2_GP_TOP_AN_STATUS1, &val); 11158c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0); 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci if ((bp->autoneg & AUTONEG_SPEED) == 0) { 11188c2ecf20Sopenharmony_ci bp->line_speed = bp->req_line_speed; 11198c2ecf20Sopenharmony_ci bp->duplex = bp->req_duplex; 11208c2ecf20Sopenharmony_ci return 0; 11218c2ecf20Sopenharmony_ci } 11228c2ecf20Sopenharmony_ci speed = val & MII_BNX2_GP_TOP_AN_SPEED_MSK; 11238c2ecf20Sopenharmony_ci switch (speed) { 11248c2ecf20Sopenharmony_ci case MII_BNX2_GP_TOP_AN_SPEED_10: 11258c2ecf20Sopenharmony_ci bp->line_speed = SPEED_10; 11268c2ecf20Sopenharmony_ci break; 11278c2ecf20Sopenharmony_ci case MII_BNX2_GP_TOP_AN_SPEED_100: 11288c2ecf20Sopenharmony_ci bp->line_speed = SPEED_100; 11298c2ecf20Sopenharmony_ci break; 11308c2ecf20Sopenharmony_ci case MII_BNX2_GP_TOP_AN_SPEED_1G: 11318c2ecf20Sopenharmony_ci case MII_BNX2_GP_TOP_AN_SPEED_1GKV: 11328c2ecf20Sopenharmony_ci bp->line_speed = SPEED_1000; 11338c2ecf20Sopenharmony_ci break; 11348c2ecf20Sopenharmony_ci case MII_BNX2_GP_TOP_AN_SPEED_2_5G: 11358c2ecf20Sopenharmony_ci bp->line_speed = SPEED_2500; 11368c2ecf20Sopenharmony_ci break; 11378c2ecf20Sopenharmony_ci } 11388c2ecf20Sopenharmony_ci if (val & MII_BNX2_GP_TOP_AN_FD) 11398c2ecf20Sopenharmony_ci bp->duplex = DUPLEX_FULL; 11408c2ecf20Sopenharmony_ci else 11418c2ecf20Sopenharmony_ci bp->duplex = DUPLEX_HALF; 11428c2ecf20Sopenharmony_ci return 0; 11438c2ecf20Sopenharmony_ci} 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_cistatic int 11468c2ecf20Sopenharmony_cibnx2_5708s_linkup(struct bnx2 *bp) 11478c2ecf20Sopenharmony_ci{ 11488c2ecf20Sopenharmony_ci u32 val; 11498c2ecf20Sopenharmony_ci 11508c2ecf20Sopenharmony_ci bp->link_up = 1; 11518c2ecf20Sopenharmony_ci bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val); 11528c2ecf20Sopenharmony_ci switch (val & BCM5708S_1000X_STAT1_SPEED_MASK) { 11538c2ecf20Sopenharmony_ci case BCM5708S_1000X_STAT1_SPEED_10: 11548c2ecf20Sopenharmony_ci bp->line_speed = SPEED_10; 11558c2ecf20Sopenharmony_ci break; 11568c2ecf20Sopenharmony_ci case BCM5708S_1000X_STAT1_SPEED_100: 11578c2ecf20Sopenharmony_ci bp->line_speed = SPEED_100; 11588c2ecf20Sopenharmony_ci break; 11598c2ecf20Sopenharmony_ci case BCM5708S_1000X_STAT1_SPEED_1G: 11608c2ecf20Sopenharmony_ci bp->line_speed = SPEED_1000; 11618c2ecf20Sopenharmony_ci break; 11628c2ecf20Sopenharmony_ci case BCM5708S_1000X_STAT1_SPEED_2G5: 11638c2ecf20Sopenharmony_ci bp->line_speed = SPEED_2500; 11648c2ecf20Sopenharmony_ci break; 11658c2ecf20Sopenharmony_ci } 11668c2ecf20Sopenharmony_ci if (val & BCM5708S_1000X_STAT1_FD) 11678c2ecf20Sopenharmony_ci bp->duplex = DUPLEX_FULL; 11688c2ecf20Sopenharmony_ci else 11698c2ecf20Sopenharmony_ci bp->duplex = DUPLEX_HALF; 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci return 0; 11728c2ecf20Sopenharmony_ci} 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_cistatic int 11758c2ecf20Sopenharmony_cibnx2_5706s_linkup(struct bnx2 *bp) 11768c2ecf20Sopenharmony_ci{ 11778c2ecf20Sopenharmony_ci u32 bmcr, local_adv, remote_adv, common; 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_ci bp->link_up = 1; 11808c2ecf20Sopenharmony_ci bp->line_speed = SPEED_1000; 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); 11838c2ecf20Sopenharmony_ci if (bmcr & BMCR_FULLDPLX) { 11848c2ecf20Sopenharmony_ci bp->duplex = DUPLEX_FULL; 11858c2ecf20Sopenharmony_ci } 11868c2ecf20Sopenharmony_ci else { 11878c2ecf20Sopenharmony_ci bp->duplex = DUPLEX_HALF; 11888c2ecf20Sopenharmony_ci } 11898c2ecf20Sopenharmony_ci 11908c2ecf20Sopenharmony_ci if (!(bmcr & BMCR_ANENABLE)) { 11918c2ecf20Sopenharmony_ci return 0; 11928c2ecf20Sopenharmony_ci } 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci bnx2_read_phy(bp, bp->mii_adv, &local_adv); 11958c2ecf20Sopenharmony_ci bnx2_read_phy(bp, bp->mii_lpa, &remote_adv); 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ci common = local_adv & remote_adv; 11988c2ecf20Sopenharmony_ci if (common & (ADVERTISE_1000XHALF | ADVERTISE_1000XFULL)) { 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci if (common & ADVERTISE_1000XFULL) { 12018c2ecf20Sopenharmony_ci bp->duplex = DUPLEX_FULL; 12028c2ecf20Sopenharmony_ci } 12038c2ecf20Sopenharmony_ci else { 12048c2ecf20Sopenharmony_ci bp->duplex = DUPLEX_HALF; 12058c2ecf20Sopenharmony_ci } 12068c2ecf20Sopenharmony_ci } 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci return 0; 12098c2ecf20Sopenharmony_ci} 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_cistatic int 12128c2ecf20Sopenharmony_cibnx2_copper_linkup(struct bnx2 *bp) 12138c2ecf20Sopenharmony_ci{ 12148c2ecf20Sopenharmony_ci u32 bmcr; 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci bp->phy_flags &= ~BNX2_PHY_FLAG_MDIX; 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); 12198c2ecf20Sopenharmony_ci if (bmcr & BMCR_ANENABLE) { 12208c2ecf20Sopenharmony_ci u32 local_adv, remote_adv, common; 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci bnx2_read_phy(bp, MII_CTRL1000, &local_adv); 12238c2ecf20Sopenharmony_ci bnx2_read_phy(bp, MII_STAT1000, &remote_adv); 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci common = local_adv & (remote_adv >> 2); 12268c2ecf20Sopenharmony_ci if (common & ADVERTISE_1000FULL) { 12278c2ecf20Sopenharmony_ci bp->line_speed = SPEED_1000; 12288c2ecf20Sopenharmony_ci bp->duplex = DUPLEX_FULL; 12298c2ecf20Sopenharmony_ci } 12308c2ecf20Sopenharmony_ci else if (common & ADVERTISE_1000HALF) { 12318c2ecf20Sopenharmony_ci bp->line_speed = SPEED_1000; 12328c2ecf20Sopenharmony_ci bp->duplex = DUPLEX_HALF; 12338c2ecf20Sopenharmony_ci } 12348c2ecf20Sopenharmony_ci else { 12358c2ecf20Sopenharmony_ci bnx2_read_phy(bp, bp->mii_adv, &local_adv); 12368c2ecf20Sopenharmony_ci bnx2_read_phy(bp, bp->mii_lpa, &remote_adv); 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_ci common = local_adv & remote_adv; 12398c2ecf20Sopenharmony_ci if (common & ADVERTISE_100FULL) { 12408c2ecf20Sopenharmony_ci bp->line_speed = SPEED_100; 12418c2ecf20Sopenharmony_ci bp->duplex = DUPLEX_FULL; 12428c2ecf20Sopenharmony_ci } 12438c2ecf20Sopenharmony_ci else if (common & ADVERTISE_100HALF) { 12448c2ecf20Sopenharmony_ci bp->line_speed = SPEED_100; 12458c2ecf20Sopenharmony_ci bp->duplex = DUPLEX_HALF; 12468c2ecf20Sopenharmony_ci } 12478c2ecf20Sopenharmony_ci else if (common & ADVERTISE_10FULL) { 12488c2ecf20Sopenharmony_ci bp->line_speed = SPEED_10; 12498c2ecf20Sopenharmony_ci bp->duplex = DUPLEX_FULL; 12508c2ecf20Sopenharmony_ci } 12518c2ecf20Sopenharmony_ci else if (common & ADVERTISE_10HALF) { 12528c2ecf20Sopenharmony_ci bp->line_speed = SPEED_10; 12538c2ecf20Sopenharmony_ci bp->duplex = DUPLEX_HALF; 12548c2ecf20Sopenharmony_ci } 12558c2ecf20Sopenharmony_ci else { 12568c2ecf20Sopenharmony_ci bp->line_speed = 0; 12578c2ecf20Sopenharmony_ci bp->link_up = 0; 12588c2ecf20Sopenharmony_ci } 12598c2ecf20Sopenharmony_ci } 12608c2ecf20Sopenharmony_ci } 12618c2ecf20Sopenharmony_ci else { 12628c2ecf20Sopenharmony_ci if (bmcr & BMCR_SPEED100) { 12638c2ecf20Sopenharmony_ci bp->line_speed = SPEED_100; 12648c2ecf20Sopenharmony_ci } 12658c2ecf20Sopenharmony_ci else { 12668c2ecf20Sopenharmony_ci bp->line_speed = SPEED_10; 12678c2ecf20Sopenharmony_ci } 12688c2ecf20Sopenharmony_ci if (bmcr & BMCR_FULLDPLX) { 12698c2ecf20Sopenharmony_ci bp->duplex = DUPLEX_FULL; 12708c2ecf20Sopenharmony_ci } 12718c2ecf20Sopenharmony_ci else { 12728c2ecf20Sopenharmony_ci bp->duplex = DUPLEX_HALF; 12738c2ecf20Sopenharmony_ci } 12748c2ecf20Sopenharmony_ci } 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci if (bp->link_up) { 12778c2ecf20Sopenharmony_ci u32 ext_status; 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci bnx2_read_phy(bp, MII_BNX2_EXT_STATUS, &ext_status); 12808c2ecf20Sopenharmony_ci if (ext_status & EXT_STATUS_MDIX) 12818c2ecf20Sopenharmony_ci bp->phy_flags |= BNX2_PHY_FLAG_MDIX; 12828c2ecf20Sopenharmony_ci } 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci return 0; 12858c2ecf20Sopenharmony_ci} 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_cistatic void 12888c2ecf20Sopenharmony_cibnx2_init_rx_context(struct bnx2 *bp, u32 cid) 12898c2ecf20Sopenharmony_ci{ 12908c2ecf20Sopenharmony_ci u32 val, rx_cid_addr = GET_CID_ADDR(cid); 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE; 12938c2ecf20Sopenharmony_ci val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2; 12948c2ecf20Sopenharmony_ci val |= 0x02 << 8; 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci if (bp->flow_ctrl & FLOW_CTRL_TX) 12978c2ecf20Sopenharmony_ci val |= BNX2_L2CTX_FLOW_CTRL_ENABLE; 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_CTX_TYPE, val); 13008c2ecf20Sopenharmony_ci} 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_cistatic void 13038c2ecf20Sopenharmony_cibnx2_init_all_rx_contexts(struct bnx2 *bp) 13048c2ecf20Sopenharmony_ci{ 13058c2ecf20Sopenharmony_ci int i; 13068c2ecf20Sopenharmony_ci u32 cid; 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci for (i = 0, cid = RX_CID; i < bp->num_rx_rings; i++, cid++) { 13098c2ecf20Sopenharmony_ci if (i == 1) 13108c2ecf20Sopenharmony_ci cid = RX_RSS_CID; 13118c2ecf20Sopenharmony_ci bnx2_init_rx_context(bp, cid); 13128c2ecf20Sopenharmony_ci } 13138c2ecf20Sopenharmony_ci} 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_cistatic void 13168c2ecf20Sopenharmony_cibnx2_set_mac_link(struct bnx2 *bp) 13178c2ecf20Sopenharmony_ci{ 13188c2ecf20Sopenharmony_ci u32 val; 13198c2ecf20Sopenharmony_ci 13208c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x2620); 13218c2ecf20Sopenharmony_ci if (bp->link_up && (bp->line_speed == SPEED_1000) && 13228c2ecf20Sopenharmony_ci (bp->duplex == DUPLEX_HALF)) { 13238c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x26ff); 13248c2ecf20Sopenharmony_ci } 13258c2ecf20Sopenharmony_ci 13268c2ecf20Sopenharmony_ci /* Configure the EMAC mode register. */ 13278c2ecf20Sopenharmony_ci val = BNX2_RD(bp, BNX2_EMAC_MODE); 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci val &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX | 13308c2ecf20Sopenharmony_ci BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK | 13318c2ecf20Sopenharmony_ci BNX2_EMAC_MODE_25G_MODE); 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci if (bp->link_up) { 13348c2ecf20Sopenharmony_ci switch (bp->line_speed) { 13358c2ecf20Sopenharmony_ci case SPEED_10: 13368c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) != BNX2_CHIP_5706) { 13378c2ecf20Sopenharmony_ci val |= BNX2_EMAC_MODE_PORT_MII_10M; 13388c2ecf20Sopenharmony_ci break; 13398c2ecf20Sopenharmony_ci } 13408c2ecf20Sopenharmony_ci fallthrough; 13418c2ecf20Sopenharmony_ci case SPEED_100: 13428c2ecf20Sopenharmony_ci val |= BNX2_EMAC_MODE_PORT_MII; 13438c2ecf20Sopenharmony_ci break; 13448c2ecf20Sopenharmony_ci case SPEED_2500: 13458c2ecf20Sopenharmony_ci val |= BNX2_EMAC_MODE_25G_MODE; 13468c2ecf20Sopenharmony_ci fallthrough; 13478c2ecf20Sopenharmony_ci case SPEED_1000: 13488c2ecf20Sopenharmony_ci val |= BNX2_EMAC_MODE_PORT_GMII; 13498c2ecf20Sopenharmony_ci break; 13508c2ecf20Sopenharmony_ci } 13518c2ecf20Sopenharmony_ci } 13528c2ecf20Sopenharmony_ci else { 13538c2ecf20Sopenharmony_ci val |= BNX2_EMAC_MODE_PORT_GMII; 13548c2ecf20Sopenharmony_ci } 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci /* Set the MAC to operate in the appropriate duplex mode. */ 13578c2ecf20Sopenharmony_ci if (bp->duplex == DUPLEX_HALF) 13588c2ecf20Sopenharmony_ci val |= BNX2_EMAC_MODE_HALF_DUPLEX; 13598c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_EMAC_MODE, val); 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci /* Enable/disable rx PAUSE. */ 13628c2ecf20Sopenharmony_ci bp->rx_mode &= ~BNX2_EMAC_RX_MODE_FLOW_EN; 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_ci if (bp->flow_ctrl & FLOW_CTRL_RX) 13658c2ecf20Sopenharmony_ci bp->rx_mode |= BNX2_EMAC_RX_MODE_FLOW_EN; 13668c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_EMAC_RX_MODE, bp->rx_mode); 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci /* Enable/disable tx PAUSE. */ 13698c2ecf20Sopenharmony_ci val = BNX2_RD(bp, BNX2_EMAC_TX_MODE); 13708c2ecf20Sopenharmony_ci val &= ~BNX2_EMAC_TX_MODE_FLOW_EN; 13718c2ecf20Sopenharmony_ci 13728c2ecf20Sopenharmony_ci if (bp->flow_ctrl & FLOW_CTRL_TX) 13738c2ecf20Sopenharmony_ci val |= BNX2_EMAC_TX_MODE_FLOW_EN; 13748c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_EMAC_TX_MODE, val); 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci /* Acknowledge the interrupt. */ 13778c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_EMAC_STATUS, BNX2_EMAC_STATUS_LINK_CHANGE); 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci bnx2_init_all_rx_contexts(bp); 13808c2ecf20Sopenharmony_ci} 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_cistatic void 13838c2ecf20Sopenharmony_cibnx2_enable_bmsr1(struct bnx2 *bp) 13848c2ecf20Sopenharmony_ci{ 13858c2ecf20Sopenharmony_ci if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) && 13868c2ecf20Sopenharmony_ci (BNX2_CHIP(bp) == BNX2_CHIP_5709)) 13878c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, 13888c2ecf20Sopenharmony_ci MII_BNX2_BLK_ADDR_GP_STATUS); 13898c2ecf20Sopenharmony_ci} 13908c2ecf20Sopenharmony_ci 13918c2ecf20Sopenharmony_cistatic void 13928c2ecf20Sopenharmony_cibnx2_disable_bmsr1(struct bnx2 *bp) 13938c2ecf20Sopenharmony_ci{ 13948c2ecf20Sopenharmony_ci if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) && 13958c2ecf20Sopenharmony_ci (BNX2_CHIP(bp) == BNX2_CHIP_5709)) 13968c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, 13978c2ecf20Sopenharmony_ci MII_BNX2_BLK_ADDR_COMBO_IEEEB0); 13988c2ecf20Sopenharmony_ci} 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_cistatic int 14018c2ecf20Sopenharmony_cibnx2_test_and_enable_2g5(struct bnx2 *bp) 14028c2ecf20Sopenharmony_ci{ 14038c2ecf20Sopenharmony_ci u32 up1; 14048c2ecf20Sopenharmony_ci int ret = 1; 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)) 14078c2ecf20Sopenharmony_ci return 0; 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci if (bp->autoneg & AUTONEG_SPEED) 14108c2ecf20Sopenharmony_ci bp->advertising |= ADVERTISED_2500baseX_Full; 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5709) 14138c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G); 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci bnx2_read_phy(bp, bp->mii_up1, &up1); 14168c2ecf20Sopenharmony_ci if (!(up1 & BCM5708S_UP1_2G5)) { 14178c2ecf20Sopenharmony_ci up1 |= BCM5708S_UP1_2G5; 14188c2ecf20Sopenharmony_ci bnx2_write_phy(bp, bp->mii_up1, up1); 14198c2ecf20Sopenharmony_ci ret = 0; 14208c2ecf20Sopenharmony_ci } 14218c2ecf20Sopenharmony_ci 14228c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5709) 14238c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, 14248c2ecf20Sopenharmony_ci MII_BNX2_BLK_ADDR_COMBO_IEEEB0); 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci return ret; 14278c2ecf20Sopenharmony_ci} 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_cistatic int 14308c2ecf20Sopenharmony_cibnx2_test_and_disable_2g5(struct bnx2 *bp) 14318c2ecf20Sopenharmony_ci{ 14328c2ecf20Sopenharmony_ci u32 up1; 14338c2ecf20Sopenharmony_ci int ret = 0; 14348c2ecf20Sopenharmony_ci 14358c2ecf20Sopenharmony_ci if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)) 14368c2ecf20Sopenharmony_ci return 0; 14378c2ecf20Sopenharmony_ci 14388c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5709) 14398c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G); 14408c2ecf20Sopenharmony_ci 14418c2ecf20Sopenharmony_ci bnx2_read_phy(bp, bp->mii_up1, &up1); 14428c2ecf20Sopenharmony_ci if (up1 & BCM5708S_UP1_2G5) { 14438c2ecf20Sopenharmony_ci up1 &= ~BCM5708S_UP1_2G5; 14448c2ecf20Sopenharmony_ci bnx2_write_phy(bp, bp->mii_up1, up1); 14458c2ecf20Sopenharmony_ci ret = 1; 14468c2ecf20Sopenharmony_ci } 14478c2ecf20Sopenharmony_ci 14488c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5709) 14498c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, 14508c2ecf20Sopenharmony_ci MII_BNX2_BLK_ADDR_COMBO_IEEEB0); 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci return ret; 14538c2ecf20Sopenharmony_ci} 14548c2ecf20Sopenharmony_ci 14558c2ecf20Sopenharmony_cistatic void 14568c2ecf20Sopenharmony_cibnx2_enable_forced_2g5(struct bnx2 *bp) 14578c2ecf20Sopenharmony_ci{ 14588c2ecf20Sopenharmony_ci u32 bmcr; 14598c2ecf20Sopenharmony_ci int err; 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)) 14628c2ecf20Sopenharmony_ci return; 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5709) { 14658c2ecf20Sopenharmony_ci u32 val; 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, 14688c2ecf20Sopenharmony_ci MII_BNX2_BLK_ADDR_SERDES_DIG); 14698c2ecf20Sopenharmony_ci if (!bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val)) { 14708c2ecf20Sopenharmony_ci val &= ~MII_BNX2_SD_MISC1_FORCE_MSK; 14718c2ecf20Sopenharmony_ci val |= MII_BNX2_SD_MISC1_FORCE | 14728c2ecf20Sopenharmony_ci MII_BNX2_SD_MISC1_FORCE_2_5G; 14738c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val); 14748c2ecf20Sopenharmony_ci } 14758c2ecf20Sopenharmony_ci 14768c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, 14778c2ecf20Sopenharmony_ci MII_BNX2_BLK_ADDR_COMBO_IEEEB0); 14788c2ecf20Sopenharmony_ci err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci } else if (BNX2_CHIP(bp) == BNX2_CHIP_5708) { 14818c2ecf20Sopenharmony_ci err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); 14828c2ecf20Sopenharmony_ci if (!err) 14838c2ecf20Sopenharmony_ci bmcr |= BCM5708S_BMCR_FORCE_2500; 14848c2ecf20Sopenharmony_ci } else { 14858c2ecf20Sopenharmony_ci return; 14868c2ecf20Sopenharmony_ci } 14878c2ecf20Sopenharmony_ci 14888c2ecf20Sopenharmony_ci if (err) 14898c2ecf20Sopenharmony_ci return; 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci if (bp->autoneg & AUTONEG_SPEED) { 14928c2ecf20Sopenharmony_ci bmcr &= ~BMCR_ANENABLE; 14938c2ecf20Sopenharmony_ci if (bp->req_duplex == DUPLEX_FULL) 14948c2ecf20Sopenharmony_ci bmcr |= BMCR_FULLDPLX; 14958c2ecf20Sopenharmony_ci } 14968c2ecf20Sopenharmony_ci bnx2_write_phy(bp, bp->mii_bmcr, bmcr); 14978c2ecf20Sopenharmony_ci} 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_cistatic void 15008c2ecf20Sopenharmony_cibnx2_disable_forced_2g5(struct bnx2 *bp) 15018c2ecf20Sopenharmony_ci{ 15028c2ecf20Sopenharmony_ci u32 bmcr; 15038c2ecf20Sopenharmony_ci int err; 15048c2ecf20Sopenharmony_ci 15058c2ecf20Sopenharmony_ci if (!(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)) 15068c2ecf20Sopenharmony_ci return; 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5709) { 15098c2ecf20Sopenharmony_ci u32 val; 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, 15128c2ecf20Sopenharmony_ci MII_BNX2_BLK_ADDR_SERDES_DIG); 15138c2ecf20Sopenharmony_ci if (!bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val)) { 15148c2ecf20Sopenharmony_ci val &= ~MII_BNX2_SD_MISC1_FORCE; 15158c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val); 15168c2ecf20Sopenharmony_ci } 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, 15198c2ecf20Sopenharmony_ci MII_BNX2_BLK_ADDR_COMBO_IEEEB0); 15208c2ecf20Sopenharmony_ci err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci } else if (BNX2_CHIP(bp) == BNX2_CHIP_5708) { 15238c2ecf20Sopenharmony_ci err = bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); 15248c2ecf20Sopenharmony_ci if (!err) 15258c2ecf20Sopenharmony_ci bmcr &= ~BCM5708S_BMCR_FORCE_2500; 15268c2ecf20Sopenharmony_ci } else { 15278c2ecf20Sopenharmony_ci return; 15288c2ecf20Sopenharmony_ci } 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci if (err) 15318c2ecf20Sopenharmony_ci return; 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci if (bp->autoneg & AUTONEG_SPEED) 15348c2ecf20Sopenharmony_ci bmcr |= BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_ANRESTART; 15358c2ecf20Sopenharmony_ci bnx2_write_phy(bp, bp->mii_bmcr, bmcr); 15368c2ecf20Sopenharmony_ci} 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_cistatic void 15398c2ecf20Sopenharmony_cibnx2_5706s_force_link_dn(struct bnx2 *bp, int start) 15408c2ecf20Sopenharmony_ci{ 15418c2ecf20Sopenharmony_ci u32 val; 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_SERDES_CTL); 15448c2ecf20Sopenharmony_ci bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val); 15458c2ecf20Sopenharmony_ci if (start) 15468c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val & 0xff0f); 15478c2ecf20Sopenharmony_ci else 15488c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val | 0xc0); 15498c2ecf20Sopenharmony_ci} 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_cistatic int 15528c2ecf20Sopenharmony_cibnx2_set_link(struct bnx2 *bp) 15538c2ecf20Sopenharmony_ci{ 15548c2ecf20Sopenharmony_ci u32 bmsr; 15558c2ecf20Sopenharmony_ci u8 link_up; 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci if (bp->loopback == MAC_LOOPBACK || bp->loopback == PHY_LOOPBACK) { 15588c2ecf20Sopenharmony_ci bp->link_up = 1; 15598c2ecf20Sopenharmony_ci return 0; 15608c2ecf20Sopenharmony_ci } 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) 15638c2ecf20Sopenharmony_ci return 0; 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci link_up = bp->link_up; 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci bnx2_enable_bmsr1(bp); 15688c2ecf20Sopenharmony_ci bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr); 15698c2ecf20Sopenharmony_ci bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr); 15708c2ecf20Sopenharmony_ci bnx2_disable_bmsr1(bp); 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) && 15738c2ecf20Sopenharmony_ci (BNX2_CHIP(bp) == BNX2_CHIP_5706)) { 15748c2ecf20Sopenharmony_ci u32 val, an_dbg; 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN) { 15778c2ecf20Sopenharmony_ci bnx2_5706s_force_link_dn(bp, 0); 15788c2ecf20Sopenharmony_ci bp->phy_flags &= ~BNX2_PHY_FLAG_FORCED_DOWN; 15798c2ecf20Sopenharmony_ci } 15808c2ecf20Sopenharmony_ci val = BNX2_RD(bp, BNX2_EMAC_STATUS); 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG); 15838c2ecf20Sopenharmony_ci bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg); 15848c2ecf20Sopenharmony_ci bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg); 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_ci if ((val & BNX2_EMAC_STATUS_LINK) && 15878c2ecf20Sopenharmony_ci !(an_dbg & MISC_SHDW_AN_DBG_NOSYNC)) 15888c2ecf20Sopenharmony_ci bmsr |= BMSR_LSTATUS; 15898c2ecf20Sopenharmony_ci else 15908c2ecf20Sopenharmony_ci bmsr &= ~BMSR_LSTATUS; 15918c2ecf20Sopenharmony_ci } 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci if (bmsr & BMSR_LSTATUS) { 15948c2ecf20Sopenharmony_ci bp->link_up = 1; 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) { 15978c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5706) 15988c2ecf20Sopenharmony_ci bnx2_5706s_linkup(bp); 15998c2ecf20Sopenharmony_ci else if (BNX2_CHIP(bp) == BNX2_CHIP_5708) 16008c2ecf20Sopenharmony_ci bnx2_5708s_linkup(bp); 16018c2ecf20Sopenharmony_ci else if (BNX2_CHIP(bp) == BNX2_CHIP_5709) 16028c2ecf20Sopenharmony_ci bnx2_5709s_linkup(bp); 16038c2ecf20Sopenharmony_ci } 16048c2ecf20Sopenharmony_ci else { 16058c2ecf20Sopenharmony_ci bnx2_copper_linkup(bp); 16068c2ecf20Sopenharmony_ci } 16078c2ecf20Sopenharmony_ci bnx2_resolve_flow_ctrl(bp); 16088c2ecf20Sopenharmony_ci } 16098c2ecf20Sopenharmony_ci else { 16108c2ecf20Sopenharmony_ci if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) && 16118c2ecf20Sopenharmony_ci (bp->autoneg & AUTONEG_SPEED)) 16128c2ecf20Sopenharmony_ci bnx2_disable_forced_2g5(bp); 16138c2ecf20Sopenharmony_ci 16148c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT) { 16158c2ecf20Sopenharmony_ci u32 bmcr; 16168c2ecf20Sopenharmony_ci 16178c2ecf20Sopenharmony_ci bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); 16188c2ecf20Sopenharmony_ci bmcr |= BMCR_ANENABLE; 16198c2ecf20Sopenharmony_ci bnx2_write_phy(bp, bp->mii_bmcr, bmcr); 16208c2ecf20Sopenharmony_ci 16218c2ecf20Sopenharmony_ci bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT; 16228c2ecf20Sopenharmony_ci } 16238c2ecf20Sopenharmony_ci bp->link_up = 0; 16248c2ecf20Sopenharmony_ci } 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_ci if (bp->link_up != link_up) { 16278c2ecf20Sopenharmony_ci bnx2_report_link(bp); 16288c2ecf20Sopenharmony_ci } 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_ci bnx2_set_mac_link(bp); 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ci return 0; 16338c2ecf20Sopenharmony_ci} 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_cistatic int 16368c2ecf20Sopenharmony_cibnx2_reset_phy(struct bnx2 *bp) 16378c2ecf20Sopenharmony_ci{ 16388c2ecf20Sopenharmony_ci int i; 16398c2ecf20Sopenharmony_ci u32 reg; 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_ci bnx2_write_phy(bp, bp->mii_bmcr, BMCR_RESET); 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci#define PHY_RESET_MAX_WAIT 100 16448c2ecf20Sopenharmony_ci for (i = 0; i < PHY_RESET_MAX_WAIT; i++) { 16458c2ecf20Sopenharmony_ci udelay(10); 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci bnx2_read_phy(bp, bp->mii_bmcr, ®); 16488c2ecf20Sopenharmony_ci if (!(reg & BMCR_RESET)) { 16498c2ecf20Sopenharmony_ci udelay(20); 16508c2ecf20Sopenharmony_ci break; 16518c2ecf20Sopenharmony_ci } 16528c2ecf20Sopenharmony_ci } 16538c2ecf20Sopenharmony_ci if (i == PHY_RESET_MAX_WAIT) { 16548c2ecf20Sopenharmony_ci return -EBUSY; 16558c2ecf20Sopenharmony_ci } 16568c2ecf20Sopenharmony_ci return 0; 16578c2ecf20Sopenharmony_ci} 16588c2ecf20Sopenharmony_ci 16598c2ecf20Sopenharmony_cistatic u32 16608c2ecf20Sopenharmony_cibnx2_phy_get_pause_adv(struct bnx2 *bp) 16618c2ecf20Sopenharmony_ci{ 16628c2ecf20Sopenharmony_ci u32 adv = 0; 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci if ((bp->req_flow_ctrl & (FLOW_CTRL_RX | FLOW_CTRL_TX)) == 16658c2ecf20Sopenharmony_ci (FLOW_CTRL_RX | FLOW_CTRL_TX)) { 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) { 16688c2ecf20Sopenharmony_ci adv = ADVERTISE_1000XPAUSE; 16698c2ecf20Sopenharmony_ci } 16708c2ecf20Sopenharmony_ci else { 16718c2ecf20Sopenharmony_ci adv = ADVERTISE_PAUSE_CAP; 16728c2ecf20Sopenharmony_ci } 16738c2ecf20Sopenharmony_ci } 16748c2ecf20Sopenharmony_ci else if (bp->req_flow_ctrl & FLOW_CTRL_TX) { 16758c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) { 16768c2ecf20Sopenharmony_ci adv = ADVERTISE_1000XPSE_ASYM; 16778c2ecf20Sopenharmony_ci } 16788c2ecf20Sopenharmony_ci else { 16798c2ecf20Sopenharmony_ci adv = ADVERTISE_PAUSE_ASYM; 16808c2ecf20Sopenharmony_ci } 16818c2ecf20Sopenharmony_ci } 16828c2ecf20Sopenharmony_ci else if (bp->req_flow_ctrl & FLOW_CTRL_RX) { 16838c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) { 16848c2ecf20Sopenharmony_ci adv = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM; 16858c2ecf20Sopenharmony_ci } 16868c2ecf20Sopenharmony_ci else { 16878c2ecf20Sopenharmony_ci adv = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; 16888c2ecf20Sopenharmony_ci } 16898c2ecf20Sopenharmony_ci } 16908c2ecf20Sopenharmony_ci return adv; 16918c2ecf20Sopenharmony_ci} 16928c2ecf20Sopenharmony_ci 16938c2ecf20Sopenharmony_cistatic int bnx2_fw_sync(struct bnx2 *, u32, int, int); 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_cistatic int 16968c2ecf20Sopenharmony_cibnx2_setup_remote_phy(struct bnx2 *bp, u8 port) 16978c2ecf20Sopenharmony_ci__releases(&bp->phy_lock) 16988c2ecf20Sopenharmony_ci__acquires(&bp->phy_lock) 16998c2ecf20Sopenharmony_ci{ 17008c2ecf20Sopenharmony_ci u32 speed_arg = 0, pause_adv; 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci pause_adv = bnx2_phy_get_pause_adv(bp); 17038c2ecf20Sopenharmony_ci 17048c2ecf20Sopenharmony_ci if (bp->autoneg & AUTONEG_SPEED) { 17058c2ecf20Sopenharmony_ci speed_arg |= BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG; 17068c2ecf20Sopenharmony_ci if (bp->advertising & ADVERTISED_10baseT_Half) 17078c2ecf20Sopenharmony_ci speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10HALF; 17088c2ecf20Sopenharmony_ci if (bp->advertising & ADVERTISED_10baseT_Full) 17098c2ecf20Sopenharmony_ci speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10FULL; 17108c2ecf20Sopenharmony_ci if (bp->advertising & ADVERTISED_100baseT_Half) 17118c2ecf20Sopenharmony_ci speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100HALF; 17128c2ecf20Sopenharmony_ci if (bp->advertising & ADVERTISED_100baseT_Full) 17138c2ecf20Sopenharmony_ci speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100FULL; 17148c2ecf20Sopenharmony_ci if (bp->advertising & ADVERTISED_1000baseT_Full) 17158c2ecf20Sopenharmony_ci speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_1GFULL; 17168c2ecf20Sopenharmony_ci if (bp->advertising & ADVERTISED_2500baseX_Full) 17178c2ecf20Sopenharmony_ci speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_2G5FULL; 17188c2ecf20Sopenharmony_ci } else { 17198c2ecf20Sopenharmony_ci if (bp->req_line_speed == SPEED_2500) 17208c2ecf20Sopenharmony_ci speed_arg = BNX2_NETLINK_SET_LINK_SPEED_2G5FULL; 17218c2ecf20Sopenharmony_ci else if (bp->req_line_speed == SPEED_1000) 17228c2ecf20Sopenharmony_ci speed_arg = BNX2_NETLINK_SET_LINK_SPEED_1GFULL; 17238c2ecf20Sopenharmony_ci else if (bp->req_line_speed == SPEED_100) { 17248c2ecf20Sopenharmony_ci if (bp->req_duplex == DUPLEX_FULL) 17258c2ecf20Sopenharmony_ci speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100FULL; 17268c2ecf20Sopenharmony_ci else 17278c2ecf20Sopenharmony_ci speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100HALF; 17288c2ecf20Sopenharmony_ci } else if (bp->req_line_speed == SPEED_10) { 17298c2ecf20Sopenharmony_ci if (bp->req_duplex == DUPLEX_FULL) 17308c2ecf20Sopenharmony_ci speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10FULL; 17318c2ecf20Sopenharmony_ci else 17328c2ecf20Sopenharmony_ci speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10HALF; 17338c2ecf20Sopenharmony_ci } 17348c2ecf20Sopenharmony_ci } 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci if (pause_adv & (ADVERTISE_1000XPAUSE | ADVERTISE_PAUSE_CAP)) 17378c2ecf20Sopenharmony_ci speed_arg |= BNX2_NETLINK_SET_LINK_FC_SYM_PAUSE; 17388c2ecf20Sopenharmony_ci if (pause_adv & (ADVERTISE_1000XPSE_ASYM | ADVERTISE_PAUSE_ASYM)) 17398c2ecf20Sopenharmony_ci speed_arg |= BNX2_NETLINK_SET_LINK_FC_ASYM_PAUSE; 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci if (port == PORT_TP) 17428c2ecf20Sopenharmony_ci speed_arg |= BNX2_NETLINK_SET_LINK_PHY_APP_REMOTE | 17438c2ecf20Sopenharmony_ci BNX2_NETLINK_SET_LINK_ETH_AT_WIRESPEED; 17448c2ecf20Sopenharmony_ci 17458c2ecf20Sopenharmony_ci bnx2_shmem_wr(bp, BNX2_DRV_MB_ARG0, speed_arg); 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ci spin_unlock_bh(&bp->phy_lock); 17488c2ecf20Sopenharmony_ci bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_CMD_SET_LINK, 1, 0); 17498c2ecf20Sopenharmony_ci spin_lock_bh(&bp->phy_lock); 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_ci return 0; 17528c2ecf20Sopenharmony_ci} 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_cistatic int 17558c2ecf20Sopenharmony_cibnx2_setup_serdes_phy(struct bnx2 *bp, u8 port) 17568c2ecf20Sopenharmony_ci__releases(&bp->phy_lock) 17578c2ecf20Sopenharmony_ci__acquires(&bp->phy_lock) 17588c2ecf20Sopenharmony_ci{ 17598c2ecf20Sopenharmony_ci u32 adv, bmcr; 17608c2ecf20Sopenharmony_ci u32 new_adv = 0; 17618c2ecf20Sopenharmony_ci 17628c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) 17638c2ecf20Sopenharmony_ci return bnx2_setup_remote_phy(bp, port); 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci if (!(bp->autoneg & AUTONEG_SPEED)) { 17668c2ecf20Sopenharmony_ci u32 new_bmcr; 17678c2ecf20Sopenharmony_ci int force_link_down = 0; 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_ci if (bp->req_line_speed == SPEED_2500) { 17708c2ecf20Sopenharmony_ci if (!bnx2_test_and_enable_2g5(bp)) 17718c2ecf20Sopenharmony_ci force_link_down = 1; 17728c2ecf20Sopenharmony_ci } else if (bp->req_line_speed == SPEED_1000) { 17738c2ecf20Sopenharmony_ci if (bnx2_test_and_disable_2g5(bp)) 17748c2ecf20Sopenharmony_ci force_link_down = 1; 17758c2ecf20Sopenharmony_ci } 17768c2ecf20Sopenharmony_ci bnx2_read_phy(bp, bp->mii_adv, &adv); 17778c2ecf20Sopenharmony_ci adv &= ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF); 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); 17808c2ecf20Sopenharmony_ci new_bmcr = bmcr & ~BMCR_ANENABLE; 17818c2ecf20Sopenharmony_ci new_bmcr |= BMCR_SPEED1000; 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5709) { 17848c2ecf20Sopenharmony_ci if (bp->req_line_speed == SPEED_2500) 17858c2ecf20Sopenharmony_ci bnx2_enable_forced_2g5(bp); 17868c2ecf20Sopenharmony_ci else if (bp->req_line_speed == SPEED_1000) { 17878c2ecf20Sopenharmony_ci bnx2_disable_forced_2g5(bp); 17888c2ecf20Sopenharmony_ci new_bmcr &= ~0x2000; 17898c2ecf20Sopenharmony_ci } 17908c2ecf20Sopenharmony_ci 17918c2ecf20Sopenharmony_ci } else if (BNX2_CHIP(bp) == BNX2_CHIP_5708) { 17928c2ecf20Sopenharmony_ci if (bp->req_line_speed == SPEED_2500) 17938c2ecf20Sopenharmony_ci new_bmcr |= BCM5708S_BMCR_FORCE_2500; 17948c2ecf20Sopenharmony_ci else 17958c2ecf20Sopenharmony_ci new_bmcr = bmcr & ~BCM5708S_BMCR_FORCE_2500; 17968c2ecf20Sopenharmony_ci } 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci if (bp->req_duplex == DUPLEX_FULL) { 17998c2ecf20Sopenharmony_ci adv |= ADVERTISE_1000XFULL; 18008c2ecf20Sopenharmony_ci new_bmcr |= BMCR_FULLDPLX; 18018c2ecf20Sopenharmony_ci } 18028c2ecf20Sopenharmony_ci else { 18038c2ecf20Sopenharmony_ci adv |= ADVERTISE_1000XHALF; 18048c2ecf20Sopenharmony_ci new_bmcr &= ~BMCR_FULLDPLX; 18058c2ecf20Sopenharmony_ci } 18068c2ecf20Sopenharmony_ci if ((new_bmcr != bmcr) || (force_link_down)) { 18078c2ecf20Sopenharmony_ci /* Force a link down visible on the other side */ 18088c2ecf20Sopenharmony_ci if (bp->link_up) { 18098c2ecf20Sopenharmony_ci bnx2_write_phy(bp, bp->mii_adv, adv & 18108c2ecf20Sopenharmony_ci ~(ADVERTISE_1000XFULL | 18118c2ecf20Sopenharmony_ci ADVERTISE_1000XHALF)); 18128c2ecf20Sopenharmony_ci bnx2_write_phy(bp, bp->mii_bmcr, bmcr | 18138c2ecf20Sopenharmony_ci BMCR_ANRESTART | BMCR_ANENABLE); 18148c2ecf20Sopenharmony_ci 18158c2ecf20Sopenharmony_ci bp->link_up = 0; 18168c2ecf20Sopenharmony_ci netif_carrier_off(bp->dev); 18178c2ecf20Sopenharmony_ci bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr); 18188c2ecf20Sopenharmony_ci bnx2_report_link(bp); 18198c2ecf20Sopenharmony_ci } 18208c2ecf20Sopenharmony_ci bnx2_write_phy(bp, bp->mii_adv, adv); 18218c2ecf20Sopenharmony_ci bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr); 18228c2ecf20Sopenharmony_ci } else { 18238c2ecf20Sopenharmony_ci bnx2_resolve_flow_ctrl(bp); 18248c2ecf20Sopenharmony_ci bnx2_set_mac_link(bp); 18258c2ecf20Sopenharmony_ci } 18268c2ecf20Sopenharmony_ci return 0; 18278c2ecf20Sopenharmony_ci } 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci bnx2_test_and_enable_2g5(bp); 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_ci if (bp->advertising & ADVERTISED_1000baseT_Full) 18328c2ecf20Sopenharmony_ci new_adv |= ADVERTISE_1000XFULL; 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_ci new_adv |= bnx2_phy_get_pause_adv(bp); 18358c2ecf20Sopenharmony_ci 18368c2ecf20Sopenharmony_ci bnx2_read_phy(bp, bp->mii_adv, &adv); 18378c2ecf20Sopenharmony_ci bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci bp->serdes_an_pending = 0; 18408c2ecf20Sopenharmony_ci if ((adv != new_adv) || ((bmcr & BMCR_ANENABLE) == 0)) { 18418c2ecf20Sopenharmony_ci /* Force a link down visible on the other side */ 18428c2ecf20Sopenharmony_ci if (bp->link_up) { 18438c2ecf20Sopenharmony_ci bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK); 18448c2ecf20Sopenharmony_ci spin_unlock_bh(&bp->phy_lock); 18458c2ecf20Sopenharmony_ci msleep(20); 18468c2ecf20Sopenharmony_ci spin_lock_bh(&bp->phy_lock); 18478c2ecf20Sopenharmony_ci } 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_ci bnx2_write_phy(bp, bp->mii_adv, new_adv); 18508c2ecf20Sopenharmony_ci bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART | 18518c2ecf20Sopenharmony_ci BMCR_ANENABLE); 18528c2ecf20Sopenharmony_ci /* Speed up link-up time when the link partner 18538c2ecf20Sopenharmony_ci * does not autonegotiate which is very common 18548c2ecf20Sopenharmony_ci * in blade servers. Some blade servers use 18558c2ecf20Sopenharmony_ci * IPMI for kerboard input and it's important 18568c2ecf20Sopenharmony_ci * to minimize link disruptions. Autoneg. involves 18578c2ecf20Sopenharmony_ci * exchanging base pages plus 3 next pages and 18588c2ecf20Sopenharmony_ci * normally completes in about 120 msec. 18598c2ecf20Sopenharmony_ci */ 18608c2ecf20Sopenharmony_ci bp->current_interval = BNX2_SERDES_AN_TIMEOUT; 18618c2ecf20Sopenharmony_ci bp->serdes_an_pending = 1; 18628c2ecf20Sopenharmony_ci mod_timer(&bp->timer, jiffies + bp->current_interval); 18638c2ecf20Sopenharmony_ci } else { 18648c2ecf20Sopenharmony_ci bnx2_resolve_flow_ctrl(bp); 18658c2ecf20Sopenharmony_ci bnx2_set_mac_link(bp); 18668c2ecf20Sopenharmony_ci } 18678c2ecf20Sopenharmony_ci 18688c2ecf20Sopenharmony_ci return 0; 18698c2ecf20Sopenharmony_ci} 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_ci#define ETHTOOL_ALL_FIBRE_SPEED \ 18728c2ecf20Sopenharmony_ci (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) ? \ 18738c2ecf20Sopenharmony_ci (ADVERTISED_2500baseX_Full | ADVERTISED_1000baseT_Full) :\ 18748c2ecf20Sopenharmony_ci (ADVERTISED_1000baseT_Full) 18758c2ecf20Sopenharmony_ci 18768c2ecf20Sopenharmony_ci#define ETHTOOL_ALL_COPPER_SPEED \ 18778c2ecf20Sopenharmony_ci (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \ 18788c2ecf20Sopenharmony_ci ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \ 18798c2ecf20Sopenharmony_ci ADVERTISED_1000baseT_Full) 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci#define PHY_ALL_10_100_SPEED (ADVERTISE_10HALF | ADVERTISE_10FULL | \ 18828c2ecf20Sopenharmony_ci ADVERTISE_100HALF | ADVERTISE_100FULL | ADVERTISE_CSMA) 18838c2ecf20Sopenharmony_ci 18848c2ecf20Sopenharmony_ci#define PHY_ALL_1000_SPEED (ADVERTISE_1000HALF | ADVERTISE_1000FULL) 18858c2ecf20Sopenharmony_ci 18868c2ecf20Sopenharmony_cistatic void 18878c2ecf20Sopenharmony_cibnx2_set_default_remote_link(struct bnx2 *bp) 18888c2ecf20Sopenharmony_ci{ 18898c2ecf20Sopenharmony_ci u32 link; 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci if (bp->phy_port == PORT_TP) 18928c2ecf20Sopenharmony_ci link = bnx2_shmem_rd(bp, BNX2_RPHY_COPPER_LINK); 18938c2ecf20Sopenharmony_ci else 18948c2ecf20Sopenharmony_ci link = bnx2_shmem_rd(bp, BNX2_RPHY_SERDES_LINK); 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_ci if (link & BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG) { 18978c2ecf20Sopenharmony_ci bp->req_line_speed = 0; 18988c2ecf20Sopenharmony_ci bp->autoneg |= AUTONEG_SPEED; 18998c2ecf20Sopenharmony_ci bp->advertising = ADVERTISED_Autoneg; 19008c2ecf20Sopenharmony_ci if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF) 19018c2ecf20Sopenharmony_ci bp->advertising |= ADVERTISED_10baseT_Half; 19028c2ecf20Sopenharmony_ci if (link & BNX2_NETLINK_SET_LINK_SPEED_10FULL) 19038c2ecf20Sopenharmony_ci bp->advertising |= ADVERTISED_10baseT_Full; 19048c2ecf20Sopenharmony_ci if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF) 19058c2ecf20Sopenharmony_ci bp->advertising |= ADVERTISED_100baseT_Half; 19068c2ecf20Sopenharmony_ci if (link & BNX2_NETLINK_SET_LINK_SPEED_100FULL) 19078c2ecf20Sopenharmony_ci bp->advertising |= ADVERTISED_100baseT_Full; 19088c2ecf20Sopenharmony_ci if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL) 19098c2ecf20Sopenharmony_ci bp->advertising |= ADVERTISED_1000baseT_Full; 19108c2ecf20Sopenharmony_ci if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL) 19118c2ecf20Sopenharmony_ci bp->advertising |= ADVERTISED_2500baseX_Full; 19128c2ecf20Sopenharmony_ci } else { 19138c2ecf20Sopenharmony_ci bp->autoneg = 0; 19148c2ecf20Sopenharmony_ci bp->advertising = 0; 19158c2ecf20Sopenharmony_ci bp->req_duplex = DUPLEX_FULL; 19168c2ecf20Sopenharmony_ci if (link & BNX2_NETLINK_SET_LINK_SPEED_10) { 19178c2ecf20Sopenharmony_ci bp->req_line_speed = SPEED_10; 19188c2ecf20Sopenharmony_ci if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF) 19198c2ecf20Sopenharmony_ci bp->req_duplex = DUPLEX_HALF; 19208c2ecf20Sopenharmony_ci } 19218c2ecf20Sopenharmony_ci if (link & BNX2_NETLINK_SET_LINK_SPEED_100) { 19228c2ecf20Sopenharmony_ci bp->req_line_speed = SPEED_100; 19238c2ecf20Sopenharmony_ci if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF) 19248c2ecf20Sopenharmony_ci bp->req_duplex = DUPLEX_HALF; 19258c2ecf20Sopenharmony_ci } 19268c2ecf20Sopenharmony_ci if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL) 19278c2ecf20Sopenharmony_ci bp->req_line_speed = SPEED_1000; 19288c2ecf20Sopenharmony_ci if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL) 19298c2ecf20Sopenharmony_ci bp->req_line_speed = SPEED_2500; 19308c2ecf20Sopenharmony_ci } 19318c2ecf20Sopenharmony_ci} 19328c2ecf20Sopenharmony_ci 19338c2ecf20Sopenharmony_cistatic void 19348c2ecf20Sopenharmony_cibnx2_set_default_link(struct bnx2 *bp) 19358c2ecf20Sopenharmony_ci{ 19368c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) { 19378c2ecf20Sopenharmony_ci bnx2_set_default_remote_link(bp); 19388c2ecf20Sopenharmony_ci return; 19398c2ecf20Sopenharmony_ci } 19408c2ecf20Sopenharmony_ci 19418c2ecf20Sopenharmony_ci bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL; 19428c2ecf20Sopenharmony_ci bp->req_line_speed = 0; 19438c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) { 19448c2ecf20Sopenharmony_ci u32 reg; 19458c2ecf20Sopenharmony_ci 19468c2ecf20Sopenharmony_ci bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg; 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_CONFIG); 19498c2ecf20Sopenharmony_ci reg &= BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK; 19508c2ecf20Sopenharmony_ci if (reg == BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G) { 19518c2ecf20Sopenharmony_ci bp->autoneg = 0; 19528c2ecf20Sopenharmony_ci bp->req_line_speed = bp->line_speed = SPEED_1000; 19538c2ecf20Sopenharmony_ci bp->req_duplex = DUPLEX_FULL; 19548c2ecf20Sopenharmony_ci } 19558c2ecf20Sopenharmony_ci } else 19568c2ecf20Sopenharmony_ci bp->advertising = ETHTOOL_ALL_COPPER_SPEED | ADVERTISED_Autoneg; 19578c2ecf20Sopenharmony_ci} 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_cistatic void 19608c2ecf20Sopenharmony_cibnx2_send_heart_beat(struct bnx2 *bp) 19618c2ecf20Sopenharmony_ci{ 19628c2ecf20Sopenharmony_ci u32 msg; 19638c2ecf20Sopenharmony_ci u32 addr; 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ci spin_lock(&bp->indirect_lock); 19668c2ecf20Sopenharmony_ci msg = (u32) (++bp->fw_drv_pulse_wr_seq & BNX2_DRV_PULSE_SEQ_MASK); 19678c2ecf20Sopenharmony_ci addr = bp->shmem_base + BNX2_DRV_PULSE_MB; 19688c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, addr); 19698c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_PCICFG_REG_WINDOW, msg); 19708c2ecf20Sopenharmony_ci spin_unlock(&bp->indirect_lock); 19718c2ecf20Sopenharmony_ci} 19728c2ecf20Sopenharmony_ci 19738c2ecf20Sopenharmony_cistatic void 19748c2ecf20Sopenharmony_cibnx2_remote_phy_event(struct bnx2 *bp) 19758c2ecf20Sopenharmony_ci{ 19768c2ecf20Sopenharmony_ci u32 msg; 19778c2ecf20Sopenharmony_ci u8 link_up = bp->link_up; 19788c2ecf20Sopenharmony_ci u8 old_port; 19798c2ecf20Sopenharmony_ci 19808c2ecf20Sopenharmony_ci msg = bnx2_shmem_rd(bp, BNX2_LINK_STATUS); 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci if (msg & BNX2_LINK_STATUS_HEART_BEAT_EXPIRED) 19838c2ecf20Sopenharmony_ci bnx2_send_heart_beat(bp); 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_ci msg &= ~BNX2_LINK_STATUS_HEART_BEAT_EXPIRED; 19868c2ecf20Sopenharmony_ci 19878c2ecf20Sopenharmony_ci if ((msg & BNX2_LINK_STATUS_LINK_UP) == BNX2_LINK_STATUS_LINK_DOWN) 19888c2ecf20Sopenharmony_ci bp->link_up = 0; 19898c2ecf20Sopenharmony_ci else { 19908c2ecf20Sopenharmony_ci u32 speed; 19918c2ecf20Sopenharmony_ci 19928c2ecf20Sopenharmony_ci bp->link_up = 1; 19938c2ecf20Sopenharmony_ci speed = msg & BNX2_LINK_STATUS_SPEED_MASK; 19948c2ecf20Sopenharmony_ci bp->duplex = DUPLEX_FULL; 19958c2ecf20Sopenharmony_ci switch (speed) { 19968c2ecf20Sopenharmony_ci case BNX2_LINK_STATUS_10HALF: 19978c2ecf20Sopenharmony_ci bp->duplex = DUPLEX_HALF; 19988c2ecf20Sopenharmony_ci fallthrough; 19998c2ecf20Sopenharmony_ci case BNX2_LINK_STATUS_10FULL: 20008c2ecf20Sopenharmony_ci bp->line_speed = SPEED_10; 20018c2ecf20Sopenharmony_ci break; 20028c2ecf20Sopenharmony_ci case BNX2_LINK_STATUS_100HALF: 20038c2ecf20Sopenharmony_ci bp->duplex = DUPLEX_HALF; 20048c2ecf20Sopenharmony_ci fallthrough; 20058c2ecf20Sopenharmony_ci case BNX2_LINK_STATUS_100BASE_T4: 20068c2ecf20Sopenharmony_ci case BNX2_LINK_STATUS_100FULL: 20078c2ecf20Sopenharmony_ci bp->line_speed = SPEED_100; 20088c2ecf20Sopenharmony_ci break; 20098c2ecf20Sopenharmony_ci case BNX2_LINK_STATUS_1000HALF: 20108c2ecf20Sopenharmony_ci bp->duplex = DUPLEX_HALF; 20118c2ecf20Sopenharmony_ci fallthrough; 20128c2ecf20Sopenharmony_ci case BNX2_LINK_STATUS_1000FULL: 20138c2ecf20Sopenharmony_ci bp->line_speed = SPEED_1000; 20148c2ecf20Sopenharmony_ci break; 20158c2ecf20Sopenharmony_ci case BNX2_LINK_STATUS_2500HALF: 20168c2ecf20Sopenharmony_ci bp->duplex = DUPLEX_HALF; 20178c2ecf20Sopenharmony_ci fallthrough; 20188c2ecf20Sopenharmony_ci case BNX2_LINK_STATUS_2500FULL: 20198c2ecf20Sopenharmony_ci bp->line_speed = SPEED_2500; 20208c2ecf20Sopenharmony_ci break; 20218c2ecf20Sopenharmony_ci default: 20228c2ecf20Sopenharmony_ci bp->line_speed = 0; 20238c2ecf20Sopenharmony_ci break; 20248c2ecf20Sopenharmony_ci } 20258c2ecf20Sopenharmony_ci 20268c2ecf20Sopenharmony_ci bp->flow_ctrl = 0; 20278c2ecf20Sopenharmony_ci if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) != 20288c2ecf20Sopenharmony_ci (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) { 20298c2ecf20Sopenharmony_ci if (bp->duplex == DUPLEX_FULL) 20308c2ecf20Sopenharmony_ci bp->flow_ctrl = bp->req_flow_ctrl; 20318c2ecf20Sopenharmony_ci } else { 20328c2ecf20Sopenharmony_ci if (msg & BNX2_LINK_STATUS_TX_FC_ENABLED) 20338c2ecf20Sopenharmony_ci bp->flow_ctrl |= FLOW_CTRL_TX; 20348c2ecf20Sopenharmony_ci if (msg & BNX2_LINK_STATUS_RX_FC_ENABLED) 20358c2ecf20Sopenharmony_ci bp->flow_ctrl |= FLOW_CTRL_RX; 20368c2ecf20Sopenharmony_ci } 20378c2ecf20Sopenharmony_ci 20388c2ecf20Sopenharmony_ci old_port = bp->phy_port; 20398c2ecf20Sopenharmony_ci if (msg & BNX2_LINK_STATUS_SERDES_LINK) 20408c2ecf20Sopenharmony_ci bp->phy_port = PORT_FIBRE; 20418c2ecf20Sopenharmony_ci else 20428c2ecf20Sopenharmony_ci bp->phy_port = PORT_TP; 20438c2ecf20Sopenharmony_ci 20448c2ecf20Sopenharmony_ci if (old_port != bp->phy_port) 20458c2ecf20Sopenharmony_ci bnx2_set_default_link(bp); 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci } 20488c2ecf20Sopenharmony_ci if (bp->link_up != link_up) 20498c2ecf20Sopenharmony_ci bnx2_report_link(bp); 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_ci bnx2_set_mac_link(bp); 20528c2ecf20Sopenharmony_ci} 20538c2ecf20Sopenharmony_ci 20548c2ecf20Sopenharmony_cistatic int 20558c2ecf20Sopenharmony_cibnx2_set_remote_link(struct bnx2 *bp) 20568c2ecf20Sopenharmony_ci{ 20578c2ecf20Sopenharmony_ci u32 evt_code; 20588c2ecf20Sopenharmony_ci 20598c2ecf20Sopenharmony_ci evt_code = bnx2_shmem_rd(bp, BNX2_FW_EVT_CODE_MB); 20608c2ecf20Sopenharmony_ci switch (evt_code) { 20618c2ecf20Sopenharmony_ci case BNX2_FW_EVT_CODE_LINK_EVENT: 20628c2ecf20Sopenharmony_ci bnx2_remote_phy_event(bp); 20638c2ecf20Sopenharmony_ci break; 20648c2ecf20Sopenharmony_ci case BNX2_FW_EVT_CODE_SW_TIMER_EXPIRATION_EVENT: 20658c2ecf20Sopenharmony_ci default: 20668c2ecf20Sopenharmony_ci bnx2_send_heart_beat(bp); 20678c2ecf20Sopenharmony_ci break; 20688c2ecf20Sopenharmony_ci } 20698c2ecf20Sopenharmony_ci return 0; 20708c2ecf20Sopenharmony_ci} 20718c2ecf20Sopenharmony_ci 20728c2ecf20Sopenharmony_cistatic int 20738c2ecf20Sopenharmony_cibnx2_setup_copper_phy(struct bnx2 *bp) 20748c2ecf20Sopenharmony_ci__releases(&bp->phy_lock) 20758c2ecf20Sopenharmony_ci__acquires(&bp->phy_lock) 20768c2ecf20Sopenharmony_ci{ 20778c2ecf20Sopenharmony_ci u32 bmcr, adv_reg, new_adv = 0; 20788c2ecf20Sopenharmony_ci u32 new_bmcr; 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_ci bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci bnx2_read_phy(bp, bp->mii_adv, &adv_reg); 20838c2ecf20Sopenharmony_ci adv_reg &= (PHY_ALL_10_100_SPEED | ADVERTISE_PAUSE_CAP | 20848c2ecf20Sopenharmony_ci ADVERTISE_PAUSE_ASYM); 20858c2ecf20Sopenharmony_ci 20868c2ecf20Sopenharmony_ci new_adv = ADVERTISE_CSMA | ethtool_adv_to_mii_adv_t(bp->advertising); 20878c2ecf20Sopenharmony_ci 20888c2ecf20Sopenharmony_ci if (bp->autoneg & AUTONEG_SPEED) { 20898c2ecf20Sopenharmony_ci u32 adv1000_reg; 20908c2ecf20Sopenharmony_ci u32 new_adv1000 = 0; 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_ci new_adv |= bnx2_phy_get_pause_adv(bp); 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci bnx2_read_phy(bp, MII_CTRL1000, &adv1000_reg); 20958c2ecf20Sopenharmony_ci adv1000_reg &= PHY_ALL_1000_SPEED; 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_ci new_adv1000 |= ethtool_adv_to_mii_ctrl1000_t(bp->advertising); 20988c2ecf20Sopenharmony_ci if ((adv1000_reg != new_adv1000) || 20998c2ecf20Sopenharmony_ci (adv_reg != new_adv) || 21008c2ecf20Sopenharmony_ci ((bmcr & BMCR_ANENABLE) == 0)) { 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci bnx2_write_phy(bp, bp->mii_adv, new_adv); 21038c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_CTRL1000, new_adv1000); 21048c2ecf20Sopenharmony_ci bnx2_write_phy(bp, bp->mii_bmcr, BMCR_ANRESTART | 21058c2ecf20Sopenharmony_ci BMCR_ANENABLE); 21068c2ecf20Sopenharmony_ci } 21078c2ecf20Sopenharmony_ci else if (bp->link_up) { 21088c2ecf20Sopenharmony_ci /* Flow ctrl may have changed from auto to forced */ 21098c2ecf20Sopenharmony_ci /* or vice-versa. */ 21108c2ecf20Sopenharmony_ci 21118c2ecf20Sopenharmony_ci bnx2_resolve_flow_ctrl(bp); 21128c2ecf20Sopenharmony_ci bnx2_set_mac_link(bp); 21138c2ecf20Sopenharmony_ci } 21148c2ecf20Sopenharmony_ci return 0; 21158c2ecf20Sopenharmony_ci } 21168c2ecf20Sopenharmony_ci 21178c2ecf20Sopenharmony_ci /* advertise nothing when forcing speed */ 21188c2ecf20Sopenharmony_ci if (adv_reg != new_adv) 21198c2ecf20Sopenharmony_ci bnx2_write_phy(bp, bp->mii_adv, new_adv); 21208c2ecf20Sopenharmony_ci 21218c2ecf20Sopenharmony_ci new_bmcr = 0; 21228c2ecf20Sopenharmony_ci if (bp->req_line_speed == SPEED_100) { 21238c2ecf20Sopenharmony_ci new_bmcr |= BMCR_SPEED100; 21248c2ecf20Sopenharmony_ci } 21258c2ecf20Sopenharmony_ci if (bp->req_duplex == DUPLEX_FULL) { 21268c2ecf20Sopenharmony_ci new_bmcr |= BMCR_FULLDPLX; 21278c2ecf20Sopenharmony_ci } 21288c2ecf20Sopenharmony_ci if (new_bmcr != bmcr) { 21298c2ecf20Sopenharmony_ci u32 bmsr; 21308c2ecf20Sopenharmony_ci 21318c2ecf20Sopenharmony_ci bnx2_read_phy(bp, bp->mii_bmsr, &bmsr); 21328c2ecf20Sopenharmony_ci bnx2_read_phy(bp, bp->mii_bmsr, &bmsr); 21338c2ecf20Sopenharmony_ci 21348c2ecf20Sopenharmony_ci if (bmsr & BMSR_LSTATUS) { 21358c2ecf20Sopenharmony_ci /* Force link down */ 21368c2ecf20Sopenharmony_ci bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK); 21378c2ecf20Sopenharmony_ci spin_unlock_bh(&bp->phy_lock); 21388c2ecf20Sopenharmony_ci msleep(50); 21398c2ecf20Sopenharmony_ci spin_lock_bh(&bp->phy_lock); 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_ci bnx2_read_phy(bp, bp->mii_bmsr, &bmsr); 21428c2ecf20Sopenharmony_ci bnx2_read_phy(bp, bp->mii_bmsr, &bmsr); 21438c2ecf20Sopenharmony_ci } 21448c2ecf20Sopenharmony_ci 21458c2ecf20Sopenharmony_ci bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr); 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_ci /* Normally, the new speed is setup after the link has 21488c2ecf20Sopenharmony_ci * gone down and up again. In some cases, link will not go 21498c2ecf20Sopenharmony_ci * down so we need to set up the new speed here. 21508c2ecf20Sopenharmony_ci */ 21518c2ecf20Sopenharmony_ci if (bmsr & BMSR_LSTATUS) { 21528c2ecf20Sopenharmony_ci bp->line_speed = bp->req_line_speed; 21538c2ecf20Sopenharmony_ci bp->duplex = bp->req_duplex; 21548c2ecf20Sopenharmony_ci bnx2_resolve_flow_ctrl(bp); 21558c2ecf20Sopenharmony_ci bnx2_set_mac_link(bp); 21568c2ecf20Sopenharmony_ci } 21578c2ecf20Sopenharmony_ci } else { 21588c2ecf20Sopenharmony_ci bnx2_resolve_flow_ctrl(bp); 21598c2ecf20Sopenharmony_ci bnx2_set_mac_link(bp); 21608c2ecf20Sopenharmony_ci } 21618c2ecf20Sopenharmony_ci return 0; 21628c2ecf20Sopenharmony_ci} 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_cistatic int 21658c2ecf20Sopenharmony_cibnx2_setup_phy(struct bnx2 *bp, u8 port) 21668c2ecf20Sopenharmony_ci__releases(&bp->phy_lock) 21678c2ecf20Sopenharmony_ci__acquires(&bp->phy_lock) 21688c2ecf20Sopenharmony_ci{ 21698c2ecf20Sopenharmony_ci if (bp->loopback == MAC_LOOPBACK) 21708c2ecf20Sopenharmony_ci return 0; 21718c2ecf20Sopenharmony_ci 21728c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) { 21738c2ecf20Sopenharmony_ci return bnx2_setup_serdes_phy(bp, port); 21748c2ecf20Sopenharmony_ci } 21758c2ecf20Sopenharmony_ci else { 21768c2ecf20Sopenharmony_ci return bnx2_setup_copper_phy(bp); 21778c2ecf20Sopenharmony_ci } 21788c2ecf20Sopenharmony_ci} 21798c2ecf20Sopenharmony_ci 21808c2ecf20Sopenharmony_cistatic int 21818c2ecf20Sopenharmony_cibnx2_init_5709s_phy(struct bnx2 *bp, int reset_phy) 21828c2ecf20Sopenharmony_ci{ 21838c2ecf20Sopenharmony_ci u32 val; 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_ci bp->mii_bmcr = MII_BMCR + 0x10; 21868c2ecf20Sopenharmony_ci bp->mii_bmsr = MII_BMSR + 0x10; 21878c2ecf20Sopenharmony_ci bp->mii_bmsr1 = MII_BNX2_GP_TOP_AN_STATUS1; 21888c2ecf20Sopenharmony_ci bp->mii_adv = MII_ADVERTISE + 0x10; 21898c2ecf20Sopenharmony_ci bp->mii_lpa = MII_LPA + 0x10; 21908c2ecf20Sopenharmony_ci bp->mii_up1 = MII_BNX2_OVER1G_UP1; 21918c2ecf20Sopenharmony_ci 21928c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_AER); 21938c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_AER_AER, MII_BNX2_AER_AER_AN_MMD); 21948c2ecf20Sopenharmony_ci 21958c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0); 21968c2ecf20Sopenharmony_ci if (reset_phy) 21978c2ecf20Sopenharmony_ci bnx2_reset_phy(bp); 21988c2ecf20Sopenharmony_ci 21998c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_SERDES_DIG); 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_ci bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, &val); 22028c2ecf20Sopenharmony_ci val &= ~MII_BNX2_SD_1000XCTL1_AUTODET; 22038c2ecf20Sopenharmony_ci val |= MII_BNX2_SD_1000XCTL1_FIBER; 22048c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, val); 22058c2ecf20Sopenharmony_ci 22068c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G); 22078c2ecf20Sopenharmony_ci bnx2_read_phy(bp, MII_BNX2_OVER1G_UP1, &val); 22088c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) 22098c2ecf20Sopenharmony_ci val |= BCM5708S_UP1_2G5; 22108c2ecf20Sopenharmony_ci else 22118c2ecf20Sopenharmony_ci val &= ~BCM5708S_UP1_2G5; 22128c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_OVER1G_UP1, val); 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_BAM_NXTPG); 22158c2ecf20Sopenharmony_ci bnx2_read_phy(bp, MII_BNX2_BAM_NXTPG_CTL, &val); 22168c2ecf20Sopenharmony_ci val |= MII_BNX2_NXTPG_CTL_T2 | MII_BNX2_NXTPG_CTL_BAM; 22178c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_BAM_NXTPG_CTL, val); 22188c2ecf20Sopenharmony_ci 22198c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_CL73_USERB0); 22208c2ecf20Sopenharmony_ci 22218c2ecf20Sopenharmony_ci val = MII_BNX2_CL73_BAM_EN | MII_BNX2_CL73_BAM_STA_MGR_EN | 22228c2ecf20Sopenharmony_ci MII_BNX2_CL73_BAM_NP_AFT_BP_EN; 22238c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_CL73_BAM_CTL1, val); 22248c2ecf20Sopenharmony_ci 22258c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0); 22268c2ecf20Sopenharmony_ci 22278c2ecf20Sopenharmony_ci return 0; 22288c2ecf20Sopenharmony_ci} 22298c2ecf20Sopenharmony_ci 22308c2ecf20Sopenharmony_cistatic int 22318c2ecf20Sopenharmony_cibnx2_init_5708s_phy(struct bnx2 *bp, int reset_phy) 22328c2ecf20Sopenharmony_ci{ 22338c2ecf20Sopenharmony_ci u32 val; 22348c2ecf20Sopenharmony_ci 22358c2ecf20Sopenharmony_ci if (reset_phy) 22368c2ecf20Sopenharmony_ci bnx2_reset_phy(bp); 22378c2ecf20Sopenharmony_ci 22388c2ecf20Sopenharmony_ci bp->mii_up1 = BCM5708S_UP1; 22398c2ecf20Sopenharmony_ci 22408c2ecf20Sopenharmony_ci bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG3); 22418c2ecf20Sopenharmony_ci bnx2_write_phy(bp, BCM5708S_DIG_3_0, BCM5708S_DIG_3_0_USE_IEEE); 22428c2ecf20Sopenharmony_ci bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG); 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci bnx2_read_phy(bp, BCM5708S_1000X_CTL1, &val); 22458c2ecf20Sopenharmony_ci val |= BCM5708S_1000X_CTL1_FIBER_MODE | BCM5708S_1000X_CTL1_AUTODET_EN; 22468c2ecf20Sopenharmony_ci bnx2_write_phy(bp, BCM5708S_1000X_CTL1, val); 22478c2ecf20Sopenharmony_ci 22488c2ecf20Sopenharmony_ci bnx2_read_phy(bp, BCM5708S_1000X_CTL2, &val); 22498c2ecf20Sopenharmony_ci val |= BCM5708S_1000X_CTL2_PLLEL_DET_EN; 22508c2ecf20Sopenharmony_ci bnx2_write_phy(bp, BCM5708S_1000X_CTL2, val); 22518c2ecf20Sopenharmony_ci 22528c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) { 22538c2ecf20Sopenharmony_ci bnx2_read_phy(bp, BCM5708S_UP1, &val); 22548c2ecf20Sopenharmony_ci val |= BCM5708S_UP1_2G5; 22558c2ecf20Sopenharmony_ci bnx2_write_phy(bp, BCM5708S_UP1, val); 22568c2ecf20Sopenharmony_ci } 22578c2ecf20Sopenharmony_ci 22588c2ecf20Sopenharmony_ci if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_A0) || 22598c2ecf20Sopenharmony_ci (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_B0) || 22608c2ecf20Sopenharmony_ci (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_B1)) { 22618c2ecf20Sopenharmony_ci /* increase tx signal amplitude */ 22628c2ecf20Sopenharmony_ci bnx2_write_phy(bp, BCM5708S_BLK_ADDR, 22638c2ecf20Sopenharmony_ci BCM5708S_BLK_ADDR_TX_MISC); 22648c2ecf20Sopenharmony_ci bnx2_read_phy(bp, BCM5708S_TX_ACTL1, &val); 22658c2ecf20Sopenharmony_ci val &= ~BCM5708S_TX_ACTL1_DRIVER_VCM; 22668c2ecf20Sopenharmony_ci bnx2_write_phy(bp, BCM5708S_TX_ACTL1, val); 22678c2ecf20Sopenharmony_ci bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG); 22688c2ecf20Sopenharmony_ci } 22698c2ecf20Sopenharmony_ci 22708c2ecf20Sopenharmony_ci val = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_CONFIG) & 22718c2ecf20Sopenharmony_ci BNX2_PORT_HW_CFG_CFG_TXCTL3_MASK; 22728c2ecf20Sopenharmony_ci 22738c2ecf20Sopenharmony_ci if (val) { 22748c2ecf20Sopenharmony_ci u32 is_backplane; 22758c2ecf20Sopenharmony_ci 22768c2ecf20Sopenharmony_ci is_backplane = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG); 22778c2ecf20Sopenharmony_ci if (is_backplane & BNX2_SHARED_HW_CFG_PHY_BACKPLANE) { 22788c2ecf20Sopenharmony_ci bnx2_write_phy(bp, BCM5708S_BLK_ADDR, 22798c2ecf20Sopenharmony_ci BCM5708S_BLK_ADDR_TX_MISC); 22808c2ecf20Sopenharmony_ci bnx2_write_phy(bp, BCM5708S_TX_ACTL3, val); 22818c2ecf20Sopenharmony_ci bnx2_write_phy(bp, BCM5708S_BLK_ADDR, 22828c2ecf20Sopenharmony_ci BCM5708S_BLK_ADDR_DIG); 22838c2ecf20Sopenharmony_ci } 22848c2ecf20Sopenharmony_ci } 22858c2ecf20Sopenharmony_ci return 0; 22868c2ecf20Sopenharmony_ci} 22878c2ecf20Sopenharmony_ci 22888c2ecf20Sopenharmony_cistatic int 22898c2ecf20Sopenharmony_cibnx2_init_5706s_phy(struct bnx2 *bp, int reset_phy) 22908c2ecf20Sopenharmony_ci{ 22918c2ecf20Sopenharmony_ci if (reset_phy) 22928c2ecf20Sopenharmony_ci bnx2_reset_phy(bp); 22938c2ecf20Sopenharmony_ci 22948c2ecf20Sopenharmony_ci bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT; 22958c2ecf20Sopenharmony_ci 22968c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5706) 22978c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_MISC_GP_HW_CTL0, 0x300); 22988c2ecf20Sopenharmony_ci 22998c2ecf20Sopenharmony_ci if (bp->dev->mtu > ETH_DATA_LEN) { 23008c2ecf20Sopenharmony_ci u32 val; 23018c2ecf20Sopenharmony_ci 23028c2ecf20Sopenharmony_ci /* Set extended packet length bit */ 23038c2ecf20Sopenharmony_ci bnx2_write_phy(bp, 0x18, 0x7); 23048c2ecf20Sopenharmony_ci bnx2_read_phy(bp, 0x18, &val); 23058c2ecf20Sopenharmony_ci bnx2_write_phy(bp, 0x18, (val & 0xfff8) | 0x4000); 23068c2ecf20Sopenharmony_ci 23078c2ecf20Sopenharmony_ci bnx2_write_phy(bp, 0x1c, 0x6c00); 23088c2ecf20Sopenharmony_ci bnx2_read_phy(bp, 0x1c, &val); 23098c2ecf20Sopenharmony_ci bnx2_write_phy(bp, 0x1c, (val & 0x3ff) | 0xec02); 23108c2ecf20Sopenharmony_ci } 23118c2ecf20Sopenharmony_ci else { 23128c2ecf20Sopenharmony_ci u32 val; 23138c2ecf20Sopenharmony_ci 23148c2ecf20Sopenharmony_ci bnx2_write_phy(bp, 0x18, 0x7); 23158c2ecf20Sopenharmony_ci bnx2_read_phy(bp, 0x18, &val); 23168c2ecf20Sopenharmony_ci bnx2_write_phy(bp, 0x18, val & ~0x4007); 23178c2ecf20Sopenharmony_ci 23188c2ecf20Sopenharmony_ci bnx2_write_phy(bp, 0x1c, 0x6c00); 23198c2ecf20Sopenharmony_ci bnx2_read_phy(bp, 0x1c, &val); 23208c2ecf20Sopenharmony_ci bnx2_write_phy(bp, 0x1c, (val & 0x3fd) | 0xec00); 23218c2ecf20Sopenharmony_ci } 23228c2ecf20Sopenharmony_ci 23238c2ecf20Sopenharmony_ci return 0; 23248c2ecf20Sopenharmony_ci} 23258c2ecf20Sopenharmony_ci 23268c2ecf20Sopenharmony_cistatic int 23278c2ecf20Sopenharmony_cibnx2_init_copper_phy(struct bnx2 *bp, int reset_phy) 23288c2ecf20Sopenharmony_ci{ 23298c2ecf20Sopenharmony_ci u32 val; 23308c2ecf20Sopenharmony_ci 23318c2ecf20Sopenharmony_ci if (reset_phy) 23328c2ecf20Sopenharmony_ci bnx2_reset_phy(bp); 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_CRC_FIX) { 23358c2ecf20Sopenharmony_ci bnx2_write_phy(bp, 0x18, 0x0c00); 23368c2ecf20Sopenharmony_ci bnx2_write_phy(bp, 0x17, 0x000a); 23378c2ecf20Sopenharmony_ci bnx2_write_phy(bp, 0x15, 0x310b); 23388c2ecf20Sopenharmony_ci bnx2_write_phy(bp, 0x17, 0x201f); 23398c2ecf20Sopenharmony_ci bnx2_write_phy(bp, 0x15, 0x9506); 23408c2ecf20Sopenharmony_ci bnx2_write_phy(bp, 0x17, 0x401f); 23418c2ecf20Sopenharmony_ci bnx2_write_phy(bp, 0x15, 0x14e2); 23428c2ecf20Sopenharmony_ci bnx2_write_phy(bp, 0x18, 0x0400); 23438c2ecf20Sopenharmony_ci } 23448c2ecf20Sopenharmony_ci 23458c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_DIS_EARLY_DAC) { 23468c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, 23478c2ecf20Sopenharmony_ci MII_BNX2_DSP_EXPAND_REG | 0x8); 23488c2ecf20Sopenharmony_ci bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val); 23498c2ecf20Sopenharmony_ci val &= ~(1 << 8); 23508c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val); 23518c2ecf20Sopenharmony_ci } 23528c2ecf20Sopenharmony_ci 23538c2ecf20Sopenharmony_ci if (bp->dev->mtu > ETH_DATA_LEN) { 23548c2ecf20Sopenharmony_ci /* Set extended packet length bit */ 23558c2ecf20Sopenharmony_ci bnx2_write_phy(bp, 0x18, 0x7); 23568c2ecf20Sopenharmony_ci bnx2_read_phy(bp, 0x18, &val); 23578c2ecf20Sopenharmony_ci bnx2_write_phy(bp, 0x18, val | 0x4000); 23588c2ecf20Sopenharmony_ci 23598c2ecf20Sopenharmony_ci bnx2_read_phy(bp, 0x10, &val); 23608c2ecf20Sopenharmony_ci bnx2_write_phy(bp, 0x10, val | 0x1); 23618c2ecf20Sopenharmony_ci } 23628c2ecf20Sopenharmony_ci else { 23638c2ecf20Sopenharmony_ci bnx2_write_phy(bp, 0x18, 0x7); 23648c2ecf20Sopenharmony_ci bnx2_read_phy(bp, 0x18, &val); 23658c2ecf20Sopenharmony_ci bnx2_write_phy(bp, 0x18, val & ~0x4007); 23668c2ecf20Sopenharmony_ci 23678c2ecf20Sopenharmony_ci bnx2_read_phy(bp, 0x10, &val); 23688c2ecf20Sopenharmony_ci bnx2_write_phy(bp, 0x10, val & ~0x1); 23698c2ecf20Sopenharmony_ci } 23708c2ecf20Sopenharmony_ci 23718c2ecf20Sopenharmony_ci /* ethernet@wirespeed */ 23728c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_AUX_CTL, AUX_CTL_MISC_CTL); 23738c2ecf20Sopenharmony_ci bnx2_read_phy(bp, MII_BNX2_AUX_CTL, &val); 23748c2ecf20Sopenharmony_ci val |= AUX_CTL_MISC_CTL_WR | AUX_CTL_MISC_CTL_WIRESPEED; 23758c2ecf20Sopenharmony_ci 23768c2ecf20Sopenharmony_ci /* auto-mdix */ 23778c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5709) 23788c2ecf20Sopenharmony_ci val |= AUX_CTL_MISC_CTL_AUTOMDIX; 23798c2ecf20Sopenharmony_ci 23808c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_AUX_CTL, val); 23818c2ecf20Sopenharmony_ci return 0; 23828c2ecf20Sopenharmony_ci} 23838c2ecf20Sopenharmony_ci 23848c2ecf20Sopenharmony_ci 23858c2ecf20Sopenharmony_cistatic int 23868c2ecf20Sopenharmony_cibnx2_init_phy(struct bnx2 *bp, int reset_phy) 23878c2ecf20Sopenharmony_ci__releases(&bp->phy_lock) 23888c2ecf20Sopenharmony_ci__acquires(&bp->phy_lock) 23898c2ecf20Sopenharmony_ci{ 23908c2ecf20Sopenharmony_ci u32 val; 23918c2ecf20Sopenharmony_ci int rc = 0; 23928c2ecf20Sopenharmony_ci 23938c2ecf20Sopenharmony_ci bp->phy_flags &= ~BNX2_PHY_FLAG_INT_MODE_MASK; 23948c2ecf20Sopenharmony_ci bp->phy_flags |= BNX2_PHY_FLAG_INT_MODE_LINK_READY; 23958c2ecf20Sopenharmony_ci 23968c2ecf20Sopenharmony_ci bp->mii_bmcr = MII_BMCR; 23978c2ecf20Sopenharmony_ci bp->mii_bmsr = MII_BMSR; 23988c2ecf20Sopenharmony_ci bp->mii_bmsr1 = MII_BMSR; 23998c2ecf20Sopenharmony_ci bp->mii_adv = MII_ADVERTISE; 24008c2ecf20Sopenharmony_ci bp->mii_lpa = MII_LPA; 24018c2ecf20Sopenharmony_ci 24028c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK); 24038c2ecf20Sopenharmony_ci 24048c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) 24058c2ecf20Sopenharmony_ci goto setup_phy; 24068c2ecf20Sopenharmony_ci 24078c2ecf20Sopenharmony_ci bnx2_read_phy(bp, MII_PHYSID1, &val); 24088c2ecf20Sopenharmony_ci bp->phy_id = val << 16; 24098c2ecf20Sopenharmony_ci bnx2_read_phy(bp, MII_PHYSID2, &val); 24108c2ecf20Sopenharmony_ci bp->phy_id |= val & 0xffff; 24118c2ecf20Sopenharmony_ci 24128c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) { 24138c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5706) 24148c2ecf20Sopenharmony_ci rc = bnx2_init_5706s_phy(bp, reset_phy); 24158c2ecf20Sopenharmony_ci else if (BNX2_CHIP(bp) == BNX2_CHIP_5708) 24168c2ecf20Sopenharmony_ci rc = bnx2_init_5708s_phy(bp, reset_phy); 24178c2ecf20Sopenharmony_ci else if (BNX2_CHIP(bp) == BNX2_CHIP_5709) 24188c2ecf20Sopenharmony_ci rc = bnx2_init_5709s_phy(bp, reset_phy); 24198c2ecf20Sopenharmony_ci } 24208c2ecf20Sopenharmony_ci else { 24218c2ecf20Sopenharmony_ci rc = bnx2_init_copper_phy(bp, reset_phy); 24228c2ecf20Sopenharmony_ci } 24238c2ecf20Sopenharmony_ci 24248c2ecf20Sopenharmony_cisetup_phy: 24258c2ecf20Sopenharmony_ci if (!rc) 24268c2ecf20Sopenharmony_ci rc = bnx2_setup_phy(bp, bp->phy_port); 24278c2ecf20Sopenharmony_ci 24288c2ecf20Sopenharmony_ci return rc; 24298c2ecf20Sopenharmony_ci} 24308c2ecf20Sopenharmony_ci 24318c2ecf20Sopenharmony_cistatic int 24328c2ecf20Sopenharmony_cibnx2_set_mac_loopback(struct bnx2 *bp) 24338c2ecf20Sopenharmony_ci{ 24348c2ecf20Sopenharmony_ci u32 mac_mode; 24358c2ecf20Sopenharmony_ci 24368c2ecf20Sopenharmony_ci mac_mode = BNX2_RD(bp, BNX2_EMAC_MODE); 24378c2ecf20Sopenharmony_ci mac_mode &= ~BNX2_EMAC_MODE_PORT; 24388c2ecf20Sopenharmony_ci mac_mode |= BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK; 24398c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_EMAC_MODE, mac_mode); 24408c2ecf20Sopenharmony_ci bp->link_up = 1; 24418c2ecf20Sopenharmony_ci return 0; 24428c2ecf20Sopenharmony_ci} 24438c2ecf20Sopenharmony_ci 24448c2ecf20Sopenharmony_cistatic int bnx2_test_link(struct bnx2 *); 24458c2ecf20Sopenharmony_ci 24468c2ecf20Sopenharmony_cistatic int 24478c2ecf20Sopenharmony_cibnx2_set_phy_loopback(struct bnx2 *bp) 24488c2ecf20Sopenharmony_ci{ 24498c2ecf20Sopenharmony_ci u32 mac_mode; 24508c2ecf20Sopenharmony_ci int rc, i; 24518c2ecf20Sopenharmony_ci 24528c2ecf20Sopenharmony_ci spin_lock_bh(&bp->phy_lock); 24538c2ecf20Sopenharmony_ci rc = bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK | BMCR_FULLDPLX | 24548c2ecf20Sopenharmony_ci BMCR_SPEED1000); 24558c2ecf20Sopenharmony_ci spin_unlock_bh(&bp->phy_lock); 24568c2ecf20Sopenharmony_ci if (rc) 24578c2ecf20Sopenharmony_ci return rc; 24588c2ecf20Sopenharmony_ci 24598c2ecf20Sopenharmony_ci for (i = 0; i < 10; i++) { 24608c2ecf20Sopenharmony_ci if (bnx2_test_link(bp) == 0) 24618c2ecf20Sopenharmony_ci break; 24628c2ecf20Sopenharmony_ci msleep(100); 24638c2ecf20Sopenharmony_ci } 24648c2ecf20Sopenharmony_ci 24658c2ecf20Sopenharmony_ci mac_mode = BNX2_RD(bp, BNX2_EMAC_MODE); 24668c2ecf20Sopenharmony_ci mac_mode &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX | 24678c2ecf20Sopenharmony_ci BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK | 24688c2ecf20Sopenharmony_ci BNX2_EMAC_MODE_25G_MODE); 24698c2ecf20Sopenharmony_ci 24708c2ecf20Sopenharmony_ci mac_mode |= BNX2_EMAC_MODE_PORT_GMII; 24718c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_EMAC_MODE, mac_mode); 24728c2ecf20Sopenharmony_ci bp->link_up = 1; 24738c2ecf20Sopenharmony_ci return 0; 24748c2ecf20Sopenharmony_ci} 24758c2ecf20Sopenharmony_ci 24768c2ecf20Sopenharmony_cistatic void 24778c2ecf20Sopenharmony_cibnx2_dump_mcp_state(struct bnx2 *bp) 24788c2ecf20Sopenharmony_ci{ 24798c2ecf20Sopenharmony_ci struct net_device *dev = bp->dev; 24808c2ecf20Sopenharmony_ci u32 mcp_p0, mcp_p1; 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_ci netdev_err(dev, "<--- start MCP states dump --->\n"); 24838c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5709) { 24848c2ecf20Sopenharmony_ci mcp_p0 = BNX2_MCP_STATE_P0; 24858c2ecf20Sopenharmony_ci mcp_p1 = BNX2_MCP_STATE_P1; 24868c2ecf20Sopenharmony_ci } else { 24878c2ecf20Sopenharmony_ci mcp_p0 = BNX2_MCP_STATE_P0_5708; 24888c2ecf20Sopenharmony_ci mcp_p1 = BNX2_MCP_STATE_P1_5708; 24898c2ecf20Sopenharmony_ci } 24908c2ecf20Sopenharmony_ci netdev_err(dev, "DEBUG: MCP_STATE_P0[%08x] MCP_STATE_P1[%08x]\n", 24918c2ecf20Sopenharmony_ci bnx2_reg_rd_ind(bp, mcp_p0), bnx2_reg_rd_ind(bp, mcp_p1)); 24928c2ecf20Sopenharmony_ci netdev_err(dev, "DEBUG: MCP mode[%08x] state[%08x] evt_mask[%08x]\n", 24938c2ecf20Sopenharmony_ci bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_MODE), 24948c2ecf20Sopenharmony_ci bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_STATE), 24958c2ecf20Sopenharmony_ci bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_EVENT_MASK)); 24968c2ecf20Sopenharmony_ci netdev_err(dev, "DEBUG: pc[%08x] pc[%08x] instr[%08x]\n", 24978c2ecf20Sopenharmony_ci bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_PROGRAM_COUNTER), 24988c2ecf20Sopenharmony_ci bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_PROGRAM_COUNTER), 24998c2ecf20Sopenharmony_ci bnx2_reg_rd_ind(bp, BNX2_MCP_CPU_INSTRUCTION)); 25008c2ecf20Sopenharmony_ci netdev_err(dev, "DEBUG: shmem states:\n"); 25018c2ecf20Sopenharmony_ci netdev_err(dev, "DEBUG: drv_mb[%08x] fw_mb[%08x] link_status[%08x]", 25028c2ecf20Sopenharmony_ci bnx2_shmem_rd(bp, BNX2_DRV_MB), 25038c2ecf20Sopenharmony_ci bnx2_shmem_rd(bp, BNX2_FW_MB), 25048c2ecf20Sopenharmony_ci bnx2_shmem_rd(bp, BNX2_LINK_STATUS)); 25058c2ecf20Sopenharmony_ci pr_cont(" drv_pulse_mb[%08x]\n", bnx2_shmem_rd(bp, BNX2_DRV_PULSE_MB)); 25068c2ecf20Sopenharmony_ci netdev_err(dev, "DEBUG: dev_info_signature[%08x] reset_type[%08x]", 25078c2ecf20Sopenharmony_ci bnx2_shmem_rd(bp, BNX2_DEV_INFO_SIGNATURE), 25088c2ecf20Sopenharmony_ci bnx2_shmem_rd(bp, BNX2_BC_STATE_RESET_TYPE)); 25098c2ecf20Sopenharmony_ci pr_cont(" condition[%08x]\n", 25108c2ecf20Sopenharmony_ci bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION)); 25118c2ecf20Sopenharmony_ci DP_SHMEM_LINE(bp, BNX2_BC_RESET_TYPE); 25128c2ecf20Sopenharmony_ci DP_SHMEM_LINE(bp, 0x3cc); 25138c2ecf20Sopenharmony_ci DP_SHMEM_LINE(bp, 0x3dc); 25148c2ecf20Sopenharmony_ci DP_SHMEM_LINE(bp, 0x3ec); 25158c2ecf20Sopenharmony_ci netdev_err(dev, "DEBUG: 0x3fc[%08x]\n", bnx2_shmem_rd(bp, 0x3fc)); 25168c2ecf20Sopenharmony_ci netdev_err(dev, "<--- end MCP states dump --->\n"); 25178c2ecf20Sopenharmony_ci} 25188c2ecf20Sopenharmony_ci 25198c2ecf20Sopenharmony_cistatic int 25208c2ecf20Sopenharmony_cibnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int ack, int silent) 25218c2ecf20Sopenharmony_ci{ 25228c2ecf20Sopenharmony_ci int i; 25238c2ecf20Sopenharmony_ci u32 val; 25248c2ecf20Sopenharmony_ci 25258c2ecf20Sopenharmony_ci bp->fw_wr_seq++; 25268c2ecf20Sopenharmony_ci msg_data |= bp->fw_wr_seq; 25278c2ecf20Sopenharmony_ci bp->fw_last_msg = msg_data; 25288c2ecf20Sopenharmony_ci 25298c2ecf20Sopenharmony_ci bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data); 25308c2ecf20Sopenharmony_ci 25318c2ecf20Sopenharmony_ci if (!ack) 25328c2ecf20Sopenharmony_ci return 0; 25338c2ecf20Sopenharmony_ci 25348c2ecf20Sopenharmony_ci /* wait for an acknowledgement. */ 25358c2ecf20Sopenharmony_ci for (i = 0; i < (BNX2_FW_ACK_TIME_OUT_MS / 10); i++) { 25368c2ecf20Sopenharmony_ci msleep(10); 25378c2ecf20Sopenharmony_ci 25388c2ecf20Sopenharmony_ci val = bnx2_shmem_rd(bp, BNX2_FW_MB); 25398c2ecf20Sopenharmony_ci 25408c2ecf20Sopenharmony_ci if ((val & BNX2_FW_MSG_ACK) == (msg_data & BNX2_DRV_MSG_SEQ)) 25418c2ecf20Sopenharmony_ci break; 25428c2ecf20Sopenharmony_ci } 25438c2ecf20Sopenharmony_ci if ((msg_data & BNX2_DRV_MSG_DATA) == BNX2_DRV_MSG_DATA_WAIT0) 25448c2ecf20Sopenharmony_ci return 0; 25458c2ecf20Sopenharmony_ci 25468c2ecf20Sopenharmony_ci /* If we timed out, inform the firmware that this is the case. */ 25478c2ecf20Sopenharmony_ci if ((val & BNX2_FW_MSG_ACK) != (msg_data & BNX2_DRV_MSG_SEQ)) { 25488c2ecf20Sopenharmony_ci msg_data &= ~BNX2_DRV_MSG_CODE; 25498c2ecf20Sopenharmony_ci msg_data |= BNX2_DRV_MSG_CODE_FW_TIMEOUT; 25508c2ecf20Sopenharmony_ci 25518c2ecf20Sopenharmony_ci bnx2_shmem_wr(bp, BNX2_DRV_MB, msg_data); 25528c2ecf20Sopenharmony_ci if (!silent) { 25538c2ecf20Sopenharmony_ci pr_err("fw sync timeout, reset code = %x\n", msg_data); 25548c2ecf20Sopenharmony_ci bnx2_dump_mcp_state(bp); 25558c2ecf20Sopenharmony_ci } 25568c2ecf20Sopenharmony_ci 25578c2ecf20Sopenharmony_ci return -EBUSY; 25588c2ecf20Sopenharmony_ci } 25598c2ecf20Sopenharmony_ci 25608c2ecf20Sopenharmony_ci if ((val & BNX2_FW_MSG_STATUS_MASK) != BNX2_FW_MSG_STATUS_OK) 25618c2ecf20Sopenharmony_ci return -EIO; 25628c2ecf20Sopenharmony_ci 25638c2ecf20Sopenharmony_ci return 0; 25648c2ecf20Sopenharmony_ci} 25658c2ecf20Sopenharmony_ci 25668c2ecf20Sopenharmony_cistatic int 25678c2ecf20Sopenharmony_cibnx2_init_5709_context(struct bnx2 *bp) 25688c2ecf20Sopenharmony_ci{ 25698c2ecf20Sopenharmony_ci int i, ret = 0; 25708c2ecf20Sopenharmony_ci u32 val; 25718c2ecf20Sopenharmony_ci 25728c2ecf20Sopenharmony_ci val = BNX2_CTX_COMMAND_ENABLED | BNX2_CTX_COMMAND_MEM_INIT | (1 << 12); 25738c2ecf20Sopenharmony_ci val |= (BNX2_PAGE_BITS - 8) << 16; 25748c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_CTX_COMMAND, val); 25758c2ecf20Sopenharmony_ci for (i = 0; i < 10; i++) { 25768c2ecf20Sopenharmony_ci val = BNX2_RD(bp, BNX2_CTX_COMMAND); 25778c2ecf20Sopenharmony_ci if (!(val & BNX2_CTX_COMMAND_MEM_INIT)) 25788c2ecf20Sopenharmony_ci break; 25798c2ecf20Sopenharmony_ci udelay(2); 25808c2ecf20Sopenharmony_ci } 25818c2ecf20Sopenharmony_ci if (val & BNX2_CTX_COMMAND_MEM_INIT) 25828c2ecf20Sopenharmony_ci return -EBUSY; 25838c2ecf20Sopenharmony_ci 25848c2ecf20Sopenharmony_ci for (i = 0; i < bp->ctx_pages; i++) { 25858c2ecf20Sopenharmony_ci int j; 25868c2ecf20Sopenharmony_ci 25878c2ecf20Sopenharmony_ci if (bp->ctx_blk[i]) 25888c2ecf20Sopenharmony_ci memset(bp->ctx_blk[i], 0, BNX2_PAGE_SIZE); 25898c2ecf20Sopenharmony_ci else 25908c2ecf20Sopenharmony_ci return -ENOMEM; 25918c2ecf20Sopenharmony_ci 25928c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA0, 25938c2ecf20Sopenharmony_ci (bp->ctx_blk_mapping[i] & 0xffffffff) | 25948c2ecf20Sopenharmony_ci BNX2_CTX_HOST_PAGE_TBL_DATA0_VALID); 25958c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA1, 25968c2ecf20Sopenharmony_ci (u64) bp->ctx_blk_mapping[i] >> 32); 25978c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL, i | 25988c2ecf20Sopenharmony_ci BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ); 25998c2ecf20Sopenharmony_ci for (j = 0; j < 10; j++) { 26008c2ecf20Sopenharmony_ci 26018c2ecf20Sopenharmony_ci val = BNX2_RD(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL); 26028c2ecf20Sopenharmony_ci if (!(val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ)) 26038c2ecf20Sopenharmony_ci break; 26048c2ecf20Sopenharmony_ci udelay(5); 26058c2ecf20Sopenharmony_ci } 26068c2ecf20Sopenharmony_ci if (val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ) { 26078c2ecf20Sopenharmony_ci ret = -EBUSY; 26088c2ecf20Sopenharmony_ci break; 26098c2ecf20Sopenharmony_ci } 26108c2ecf20Sopenharmony_ci } 26118c2ecf20Sopenharmony_ci return ret; 26128c2ecf20Sopenharmony_ci} 26138c2ecf20Sopenharmony_ci 26148c2ecf20Sopenharmony_cistatic void 26158c2ecf20Sopenharmony_cibnx2_init_context(struct bnx2 *bp) 26168c2ecf20Sopenharmony_ci{ 26178c2ecf20Sopenharmony_ci u32 vcid; 26188c2ecf20Sopenharmony_ci 26198c2ecf20Sopenharmony_ci vcid = 96; 26208c2ecf20Sopenharmony_ci while (vcid) { 26218c2ecf20Sopenharmony_ci u32 vcid_addr, pcid_addr, offset; 26228c2ecf20Sopenharmony_ci int i; 26238c2ecf20Sopenharmony_ci 26248c2ecf20Sopenharmony_ci vcid--; 26258c2ecf20Sopenharmony_ci 26268c2ecf20Sopenharmony_ci if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) { 26278c2ecf20Sopenharmony_ci u32 new_vcid; 26288c2ecf20Sopenharmony_ci 26298c2ecf20Sopenharmony_ci vcid_addr = GET_PCID_ADDR(vcid); 26308c2ecf20Sopenharmony_ci if (vcid & 0x8) { 26318c2ecf20Sopenharmony_ci new_vcid = 0x60 + (vcid & 0xf0) + (vcid & 0x7); 26328c2ecf20Sopenharmony_ci } 26338c2ecf20Sopenharmony_ci else { 26348c2ecf20Sopenharmony_ci new_vcid = vcid; 26358c2ecf20Sopenharmony_ci } 26368c2ecf20Sopenharmony_ci pcid_addr = GET_PCID_ADDR(new_vcid); 26378c2ecf20Sopenharmony_ci } 26388c2ecf20Sopenharmony_ci else { 26398c2ecf20Sopenharmony_ci vcid_addr = GET_CID_ADDR(vcid); 26408c2ecf20Sopenharmony_ci pcid_addr = vcid_addr; 26418c2ecf20Sopenharmony_ci } 26428c2ecf20Sopenharmony_ci 26438c2ecf20Sopenharmony_ci for (i = 0; i < (CTX_SIZE / PHY_CTX_SIZE); i++) { 26448c2ecf20Sopenharmony_ci vcid_addr += (i << PHY_CTX_SHIFT); 26458c2ecf20Sopenharmony_ci pcid_addr += (i << PHY_CTX_SHIFT); 26468c2ecf20Sopenharmony_ci 26478c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_CTX_VIRT_ADDR, vcid_addr); 26488c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr); 26498c2ecf20Sopenharmony_ci 26508c2ecf20Sopenharmony_ci /* Zero out the context. */ 26518c2ecf20Sopenharmony_ci for (offset = 0; offset < PHY_CTX_SIZE; offset += 4) 26528c2ecf20Sopenharmony_ci bnx2_ctx_wr(bp, vcid_addr, offset, 0); 26538c2ecf20Sopenharmony_ci } 26548c2ecf20Sopenharmony_ci } 26558c2ecf20Sopenharmony_ci} 26568c2ecf20Sopenharmony_ci 26578c2ecf20Sopenharmony_cistatic int 26588c2ecf20Sopenharmony_cibnx2_alloc_bad_rbuf(struct bnx2 *bp) 26598c2ecf20Sopenharmony_ci{ 26608c2ecf20Sopenharmony_ci u16 *good_mbuf; 26618c2ecf20Sopenharmony_ci u32 good_mbuf_cnt; 26628c2ecf20Sopenharmony_ci u32 val; 26638c2ecf20Sopenharmony_ci 26648c2ecf20Sopenharmony_ci good_mbuf = kmalloc_array(512, sizeof(u16), GFP_KERNEL); 26658c2ecf20Sopenharmony_ci if (!good_mbuf) 26668c2ecf20Sopenharmony_ci return -ENOMEM; 26678c2ecf20Sopenharmony_ci 26688c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_MISC_ENABLE_SET_BITS, 26698c2ecf20Sopenharmony_ci BNX2_MISC_ENABLE_SET_BITS_RX_MBUF_ENABLE); 26708c2ecf20Sopenharmony_ci 26718c2ecf20Sopenharmony_ci good_mbuf_cnt = 0; 26728c2ecf20Sopenharmony_ci 26738c2ecf20Sopenharmony_ci /* Allocate a bunch of mbufs and save the good ones in an array. */ 26748c2ecf20Sopenharmony_ci val = bnx2_reg_rd_ind(bp, BNX2_RBUF_STATUS1); 26758c2ecf20Sopenharmony_ci while (val & BNX2_RBUF_STATUS1_FREE_COUNT) { 26768c2ecf20Sopenharmony_ci bnx2_reg_wr_ind(bp, BNX2_RBUF_COMMAND, 26778c2ecf20Sopenharmony_ci BNX2_RBUF_COMMAND_ALLOC_REQ); 26788c2ecf20Sopenharmony_ci 26798c2ecf20Sopenharmony_ci val = bnx2_reg_rd_ind(bp, BNX2_RBUF_FW_BUF_ALLOC); 26808c2ecf20Sopenharmony_ci 26818c2ecf20Sopenharmony_ci val &= BNX2_RBUF_FW_BUF_ALLOC_VALUE; 26828c2ecf20Sopenharmony_ci 26838c2ecf20Sopenharmony_ci /* The addresses with Bit 9 set are bad memory blocks. */ 26848c2ecf20Sopenharmony_ci if (!(val & (1 << 9))) { 26858c2ecf20Sopenharmony_ci good_mbuf[good_mbuf_cnt] = (u16) val; 26868c2ecf20Sopenharmony_ci good_mbuf_cnt++; 26878c2ecf20Sopenharmony_ci } 26888c2ecf20Sopenharmony_ci 26898c2ecf20Sopenharmony_ci val = bnx2_reg_rd_ind(bp, BNX2_RBUF_STATUS1); 26908c2ecf20Sopenharmony_ci } 26918c2ecf20Sopenharmony_ci 26928c2ecf20Sopenharmony_ci /* Free the good ones back to the mbuf pool thus discarding 26938c2ecf20Sopenharmony_ci * all the bad ones. */ 26948c2ecf20Sopenharmony_ci while (good_mbuf_cnt) { 26958c2ecf20Sopenharmony_ci good_mbuf_cnt--; 26968c2ecf20Sopenharmony_ci 26978c2ecf20Sopenharmony_ci val = good_mbuf[good_mbuf_cnt]; 26988c2ecf20Sopenharmony_ci val = (val << 9) | val | 1; 26998c2ecf20Sopenharmony_ci 27008c2ecf20Sopenharmony_ci bnx2_reg_wr_ind(bp, BNX2_RBUF_FW_BUF_FREE, val); 27018c2ecf20Sopenharmony_ci } 27028c2ecf20Sopenharmony_ci kfree(good_mbuf); 27038c2ecf20Sopenharmony_ci return 0; 27048c2ecf20Sopenharmony_ci} 27058c2ecf20Sopenharmony_ci 27068c2ecf20Sopenharmony_cistatic void 27078c2ecf20Sopenharmony_cibnx2_set_mac_addr(struct bnx2 *bp, u8 *mac_addr, u32 pos) 27088c2ecf20Sopenharmony_ci{ 27098c2ecf20Sopenharmony_ci u32 val; 27108c2ecf20Sopenharmony_ci 27118c2ecf20Sopenharmony_ci val = (mac_addr[0] << 8) | mac_addr[1]; 27128c2ecf20Sopenharmony_ci 27138c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_EMAC_MAC_MATCH0 + (pos * 8), val); 27148c2ecf20Sopenharmony_ci 27158c2ecf20Sopenharmony_ci val = (mac_addr[2] << 24) | (mac_addr[3] << 16) | 27168c2ecf20Sopenharmony_ci (mac_addr[4] << 8) | mac_addr[5]; 27178c2ecf20Sopenharmony_ci 27188c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_EMAC_MAC_MATCH1 + (pos * 8), val); 27198c2ecf20Sopenharmony_ci} 27208c2ecf20Sopenharmony_ci 27218c2ecf20Sopenharmony_cistatic inline int 27228c2ecf20Sopenharmony_cibnx2_alloc_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index, gfp_t gfp) 27238c2ecf20Sopenharmony_ci{ 27248c2ecf20Sopenharmony_ci dma_addr_t mapping; 27258c2ecf20Sopenharmony_ci struct bnx2_sw_pg *rx_pg = &rxr->rx_pg_ring[index]; 27268c2ecf20Sopenharmony_ci struct bnx2_rx_bd *rxbd = 27278c2ecf20Sopenharmony_ci &rxr->rx_pg_desc_ring[BNX2_RX_RING(index)][BNX2_RX_IDX(index)]; 27288c2ecf20Sopenharmony_ci struct page *page = alloc_page(gfp); 27298c2ecf20Sopenharmony_ci 27308c2ecf20Sopenharmony_ci if (!page) 27318c2ecf20Sopenharmony_ci return -ENOMEM; 27328c2ecf20Sopenharmony_ci mapping = dma_map_page(&bp->pdev->dev, page, 0, PAGE_SIZE, 27338c2ecf20Sopenharmony_ci PCI_DMA_FROMDEVICE); 27348c2ecf20Sopenharmony_ci if (dma_mapping_error(&bp->pdev->dev, mapping)) { 27358c2ecf20Sopenharmony_ci __free_page(page); 27368c2ecf20Sopenharmony_ci return -EIO; 27378c2ecf20Sopenharmony_ci } 27388c2ecf20Sopenharmony_ci 27398c2ecf20Sopenharmony_ci rx_pg->page = page; 27408c2ecf20Sopenharmony_ci dma_unmap_addr_set(rx_pg, mapping, mapping); 27418c2ecf20Sopenharmony_ci rxbd->rx_bd_haddr_hi = (u64) mapping >> 32; 27428c2ecf20Sopenharmony_ci rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff; 27438c2ecf20Sopenharmony_ci return 0; 27448c2ecf20Sopenharmony_ci} 27458c2ecf20Sopenharmony_ci 27468c2ecf20Sopenharmony_cistatic void 27478c2ecf20Sopenharmony_cibnx2_free_rx_page(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index) 27488c2ecf20Sopenharmony_ci{ 27498c2ecf20Sopenharmony_ci struct bnx2_sw_pg *rx_pg = &rxr->rx_pg_ring[index]; 27508c2ecf20Sopenharmony_ci struct page *page = rx_pg->page; 27518c2ecf20Sopenharmony_ci 27528c2ecf20Sopenharmony_ci if (!page) 27538c2ecf20Sopenharmony_ci return; 27548c2ecf20Sopenharmony_ci 27558c2ecf20Sopenharmony_ci dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(rx_pg, mapping), 27568c2ecf20Sopenharmony_ci PAGE_SIZE, PCI_DMA_FROMDEVICE); 27578c2ecf20Sopenharmony_ci 27588c2ecf20Sopenharmony_ci __free_page(page); 27598c2ecf20Sopenharmony_ci rx_pg->page = NULL; 27608c2ecf20Sopenharmony_ci} 27618c2ecf20Sopenharmony_ci 27628c2ecf20Sopenharmony_cistatic inline int 27638c2ecf20Sopenharmony_cibnx2_alloc_rx_data(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u16 index, gfp_t gfp) 27648c2ecf20Sopenharmony_ci{ 27658c2ecf20Sopenharmony_ci u8 *data; 27668c2ecf20Sopenharmony_ci struct bnx2_sw_bd *rx_buf = &rxr->rx_buf_ring[index]; 27678c2ecf20Sopenharmony_ci dma_addr_t mapping; 27688c2ecf20Sopenharmony_ci struct bnx2_rx_bd *rxbd = 27698c2ecf20Sopenharmony_ci &rxr->rx_desc_ring[BNX2_RX_RING(index)][BNX2_RX_IDX(index)]; 27708c2ecf20Sopenharmony_ci 27718c2ecf20Sopenharmony_ci data = kmalloc(bp->rx_buf_size, gfp); 27728c2ecf20Sopenharmony_ci if (!data) 27738c2ecf20Sopenharmony_ci return -ENOMEM; 27748c2ecf20Sopenharmony_ci 27758c2ecf20Sopenharmony_ci mapping = dma_map_single(&bp->pdev->dev, 27768c2ecf20Sopenharmony_ci get_l2_fhdr(data), 27778c2ecf20Sopenharmony_ci bp->rx_buf_use_size, 27788c2ecf20Sopenharmony_ci PCI_DMA_FROMDEVICE); 27798c2ecf20Sopenharmony_ci if (dma_mapping_error(&bp->pdev->dev, mapping)) { 27808c2ecf20Sopenharmony_ci kfree(data); 27818c2ecf20Sopenharmony_ci return -EIO; 27828c2ecf20Sopenharmony_ci } 27838c2ecf20Sopenharmony_ci 27848c2ecf20Sopenharmony_ci rx_buf->data = data; 27858c2ecf20Sopenharmony_ci dma_unmap_addr_set(rx_buf, mapping, mapping); 27868c2ecf20Sopenharmony_ci 27878c2ecf20Sopenharmony_ci rxbd->rx_bd_haddr_hi = (u64) mapping >> 32; 27888c2ecf20Sopenharmony_ci rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff; 27898c2ecf20Sopenharmony_ci 27908c2ecf20Sopenharmony_ci rxr->rx_prod_bseq += bp->rx_buf_use_size; 27918c2ecf20Sopenharmony_ci 27928c2ecf20Sopenharmony_ci return 0; 27938c2ecf20Sopenharmony_ci} 27948c2ecf20Sopenharmony_ci 27958c2ecf20Sopenharmony_cistatic int 27968c2ecf20Sopenharmony_cibnx2_phy_event_is_set(struct bnx2 *bp, struct bnx2_napi *bnapi, u32 event) 27978c2ecf20Sopenharmony_ci{ 27988c2ecf20Sopenharmony_ci struct status_block *sblk = bnapi->status_blk.msi; 27998c2ecf20Sopenharmony_ci u32 new_link_state, old_link_state; 28008c2ecf20Sopenharmony_ci int is_set = 1; 28018c2ecf20Sopenharmony_ci 28028c2ecf20Sopenharmony_ci new_link_state = sblk->status_attn_bits & event; 28038c2ecf20Sopenharmony_ci old_link_state = sblk->status_attn_bits_ack & event; 28048c2ecf20Sopenharmony_ci if (new_link_state != old_link_state) { 28058c2ecf20Sopenharmony_ci if (new_link_state) 28068c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_PCICFG_STATUS_BIT_SET_CMD, event); 28078c2ecf20Sopenharmony_ci else 28088c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_PCICFG_STATUS_BIT_CLEAR_CMD, event); 28098c2ecf20Sopenharmony_ci } else 28108c2ecf20Sopenharmony_ci is_set = 0; 28118c2ecf20Sopenharmony_ci 28128c2ecf20Sopenharmony_ci return is_set; 28138c2ecf20Sopenharmony_ci} 28148c2ecf20Sopenharmony_ci 28158c2ecf20Sopenharmony_cistatic void 28168c2ecf20Sopenharmony_cibnx2_phy_int(struct bnx2 *bp, struct bnx2_napi *bnapi) 28178c2ecf20Sopenharmony_ci{ 28188c2ecf20Sopenharmony_ci spin_lock(&bp->phy_lock); 28198c2ecf20Sopenharmony_ci 28208c2ecf20Sopenharmony_ci if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_LINK_STATE)) 28218c2ecf20Sopenharmony_ci bnx2_set_link(bp); 28228c2ecf20Sopenharmony_ci if (bnx2_phy_event_is_set(bp, bnapi, STATUS_ATTN_BITS_TIMER_ABORT)) 28238c2ecf20Sopenharmony_ci bnx2_set_remote_link(bp); 28248c2ecf20Sopenharmony_ci 28258c2ecf20Sopenharmony_ci spin_unlock(&bp->phy_lock); 28268c2ecf20Sopenharmony_ci 28278c2ecf20Sopenharmony_ci} 28288c2ecf20Sopenharmony_ci 28298c2ecf20Sopenharmony_cistatic inline u16 28308c2ecf20Sopenharmony_cibnx2_get_hw_tx_cons(struct bnx2_napi *bnapi) 28318c2ecf20Sopenharmony_ci{ 28328c2ecf20Sopenharmony_ci u16 cons; 28338c2ecf20Sopenharmony_ci 28348c2ecf20Sopenharmony_ci cons = READ_ONCE(*bnapi->hw_tx_cons_ptr); 28358c2ecf20Sopenharmony_ci 28368c2ecf20Sopenharmony_ci if (unlikely((cons & BNX2_MAX_TX_DESC_CNT) == BNX2_MAX_TX_DESC_CNT)) 28378c2ecf20Sopenharmony_ci cons++; 28388c2ecf20Sopenharmony_ci return cons; 28398c2ecf20Sopenharmony_ci} 28408c2ecf20Sopenharmony_ci 28418c2ecf20Sopenharmony_cistatic int 28428c2ecf20Sopenharmony_cibnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) 28438c2ecf20Sopenharmony_ci{ 28448c2ecf20Sopenharmony_ci struct bnx2_tx_ring_info *txr = &bnapi->tx_ring; 28458c2ecf20Sopenharmony_ci u16 hw_cons, sw_cons, sw_ring_cons; 28468c2ecf20Sopenharmony_ci int tx_pkt = 0, index; 28478c2ecf20Sopenharmony_ci unsigned int tx_bytes = 0; 28488c2ecf20Sopenharmony_ci struct netdev_queue *txq; 28498c2ecf20Sopenharmony_ci 28508c2ecf20Sopenharmony_ci index = (bnapi - bp->bnx2_napi); 28518c2ecf20Sopenharmony_ci txq = netdev_get_tx_queue(bp->dev, index); 28528c2ecf20Sopenharmony_ci 28538c2ecf20Sopenharmony_ci hw_cons = bnx2_get_hw_tx_cons(bnapi); 28548c2ecf20Sopenharmony_ci sw_cons = txr->tx_cons; 28558c2ecf20Sopenharmony_ci 28568c2ecf20Sopenharmony_ci while (sw_cons != hw_cons) { 28578c2ecf20Sopenharmony_ci struct bnx2_sw_tx_bd *tx_buf; 28588c2ecf20Sopenharmony_ci struct sk_buff *skb; 28598c2ecf20Sopenharmony_ci int i, last; 28608c2ecf20Sopenharmony_ci 28618c2ecf20Sopenharmony_ci sw_ring_cons = BNX2_TX_RING_IDX(sw_cons); 28628c2ecf20Sopenharmony_ci 28638c2ecf20Sopenharmony_ci tx_buf = &txr->tx_buf_ring[sw_ring_cons]; 28648c2ecf20Sopenharmony_ci skb = tx_buf->skb; 28658c2ecf20Sopenharmony_ci 28668c2ecf20Sopenharmony_ci /* prefetch skb_end_pointer() to speedup skb_shinfo(skb) */ 28678c2ecf20Sopenharmony_ci prefetch(&skb->end); 28688c2ecf20Sopenharmony_ci 28698c2ecf20Sopenharmony_ci /* partial BD completions possible with TSO packets */ 28708c2ecf20Sopenharmony_ci if (tx_buf->is_gso) { 28718c2ecf20Sopenharmony_ci u16 last_idx, last_ring_idx; 28728c2ecf20Sopenharmony_ci 28738c2ecf20Sopenharmony_ci last_idx = sw_cons + tx_buf->nr_frags + 1; 28748c2ecf20Sopenharmony_ci last_ring_idx = sw_ring_cons + tx_buf->nr_frags + 1; 28758c2ecf20Sopenharmony_ci if (unlikely(last_ring_idx >= BNX2_MAX_TX_DESC_CNT)) { 28768c2ecf20Sopenharmony_ci last_idx++; 28778c2ecf20Sopenharmony_ci } 28788c2ecf20Sopenharmony_ci if (((s16) ((s16) last_idx - (s16) hw_cons)) > 0) { 28798c2ecf20Sopenharmony_ci break; 28808c2ecf20Sopenharmony_ci } 28818c2ecf20Sopenharmony_ci } 28828c2ecf20Sopenharmony_ci 28838c2ecf20Sopenharmony_ci dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(tx_buf, mapping), 28848c2ecf20Sopenharmony_ci skb_headlen(skb), PCI_DMA_TODEVICE); 28858c2ecf20Sopenharmony_ci 28868c2ecf20Sopenharmony_ci tx_buf->skb = NULL; 28878c2ecf20Sopenharmony_ci last = tx_buf->nr_frags; 28888c2ecf20Sopenharmony_ci 28898c2ecf20Sopenharmony_ci for (i = 0; i < last; i++) { 28908c2ecf20Sopenharmony_ci struct bnx2_sw_tx_bd *tx_buf; 28918c2ecf20Sopenharmony_ci 28928c2ecf20Sopenharmony_ci sw_cons = BNX2_NEXT_TX_BD(sw_cons); 28938c2ecf20Sopenharmony_ci 28948c2ecf20Sopenharmony_ci tx_buf = &txr->tx_buf_ring[BNX2_TX_RING_IDX(sw_cons)]; 28958c2ecf20Sopenharmony_ci dma_unmap_page(&bp->pdev->dev, 28968c2ecf20Sopenharmony_ci dma_unmap_addr(tx_buf, mapping), 28978c2ecf20Sopenharmony_ci skb_frag_size(&skb_shinfo(skb)->frags[i]), 28988c2ecf20Sopenharmony_ci PCI_DMA_TODEVICE); 28998c2ecf20Sopenharmony_ci } 29008c2ecf20Sopenharmony_ci 29018c2ecf20Sopenharmony_ci sw_cons = BNX2_NEXT_TX_BD(sw_cons); 29028c2ecf20Sopenharmony_ci 29038c2ecf20Sopenharmony_ci tx_bytes += skb->len; 29048c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 29058c2ecf20Sopenharmony_ci tx_pkt++; 29068c2ecf20Sopenharmony_ci if (tx_pkt == budget) 29078c2ecf20Sopenharmony_ci break; 29088c2ecf20Sopenharmony_ci 29098c2ecf20Sopenharmony_ci if (hw_cons == sw_cons) 29108c2ecf20Sopenharmony_ci hw_cons = bnx2_get_hw_tx_cons(bnapi); 29118c2ecf20Sopenharmony_ci } 29128c2ecf20Sopenharmony_ci 29138c2ecf20Sopenharmony_ci netdev_tx_completed_queue(txq, tx_pkt, tx_bytes); 29148c2ecf20Sopenharmony_ci txr->hw_tx_cons = hw_cons; 29158c2ecf20Sopenharmony_ci txr->tx_cons = sw_cons; 29168c2ecf20Sopenharmony_ci 29178c2ecf20Sopenharmony_ci /* Need to make the tx_cons update visible to bnx2_start_xmit() 29188c2ecf20Sopenharmony_ci * before checking for netif_tx_queue_stopped(). Without the 29198c2ecf20Sopenharmony_ci * memory barrier, there is a small possibility that bnx2_start_xmit() 29208c2ecf20Sopenharmony_ci * will miss it and cause the queue to be stopped forever. 29218c2ecf20Sopenharmony_ci */ 29228c2ecf20Sopenharmony_ci smp_mb(); 29238c2ecf20Sopenharmony_ci 29248c2ecf20Sopenharmony_ci if (unlikely(netif_tx_queue_stopped(txq)) && 29258c2ecf20Sopenharmony_ci (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh)) { 29268c2ecf20Sopenharmony_ci __netif_tx_lock(txq, smp_processor_id()); 29278c2ecf20Sopenharmony_ci if ((netif_tx_queue_stopped(txq)) && 29288c2ecf20Sopenharmony_ci (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh)) 29298c2ecf20Sopenharmony_ci netif_tx_wake_queue(txq); 29308c2ecf20Sopenharmony_ci __netif_tx_unlock(txq); 29318c2ecf20Sopenharmony_ci } 29328c2ecf20Sopenharmony_ci 29338c2ecf20Sopenharmony_ci return tx_pkt; 29348c2ecf20Sopenharmony_ci} 29358c2ecf20Sopenharmony_ci 29368c2ecf20Sopenharmony_cistatic void 29378c2ecf20Sopenharmony_cibnx2_reuse_rx_skb_pages(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, 29388c2ecf20Sopenharmony_ci struct sk_buff *skb, int count) 29398c2ecf20Sopenharmony_ci{ 29408c2ecf20Sopenharmony_ci struct bnx2_sw_pg *cons_rx_pg, *prod_rx_pg; 29418c2ecf20Sopenharmony_ci struct bnx2_rx_bd *cons_bd, *prod_bd; 29428c2ecf20Sopenharmony_ci int i; 29438c2ecf20Sopenharmony_ci u16 hw_prod, prod; 29448c2ecf20Sopenharmony_ci u16 cons = rxr->rx_pg_cons; 29458c2ecf20Sopenharmony_ci 29468c2ecf20Sopenharmony_ci cons_rx_pg = &rxr->rx_pg_ring[cons]; 29478c2ecf20Sopenharmony_ci 29488c2ecf20Sopenharmony_ci /* The caller was unable to allocate a new page to replace the 29498c2ecf20Sopenharmony_ci * last one in the frags array, so we need to recycle that page 29508c2ecf20Sopenharmony_ci * and then free the skb. 29518c2ecf20Sopenharmony_ci */ 29528c2ecf20Sopenharmony_ci if (skb) { 29538c2ecf20Sopenharmony_ci struct page *page; 29548c2ecf20Sopenharmony_ci struct skb_shared_info *shinfo; 29558c2ecf20Sopenharmony_ci 29568c2ecf20Sopenharmony_ci shinfo = skb_shinfo(skb); 29578c2ecf20Sopenharmony_ci shinfo->nr_frags--; 29588c2ecf20Sopenharmony_ci page = skb_frag_page(&shinfo->frags[shinfo->nr_frags]); 29598c2ecf20Sopenharmony_ci __skb_frag_set_page(&shinfo->frags[shinfo->nr_frags], NULL); 29608c2ecf20Sopenharmony_ci 29618c2ecf20Sopenharmony_ci cons_rx_pg->page = page; 29628c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 29638c2ecf20Sopenharmony_ci } 29648c2ecf20Sopenharmony_ci 29658c2ecf20Sopenharmony_ci hw_prod = rxr->rx_pg_prod; 29668c2ecf20Sopenharmony_ci 29678c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 29688c2ecf20Sopenharmony_ci prod = BNX2_RX_PG_RING_IDX(hw_prod); 29698c2ecf20Sopenharmony_ci 29708c2ecf20Sopenharmony_ci prod_rx_pg = &rxr->rx_pg_ring[prod]; 29718c2ecf20Sopenharmony_ci cons_rx_pg = &rxr->rx_pg_ring[cons]; 29728c2ecf20Sopenharmony_ci cons_bd = &rxr->rx_pg_desc_ring[BNX2_RX_RING(cons)] 29738c2ecf20Sopenharmony_ci [BNX2_RX_IDX(cons)]; 29748c2ecf20Sopenharmony_ci prod_bd = &rxr->rx_pg_desc_ring[BNX2_RX_RING(prod)] 29758c2ecf20Sopenharmony_ci [BNX2_RX_IDX(prod)]; 29768c2ecf20Sopenharmony_ci 29778c2ecf20Sopenharmony_ci if (prod != cons) { 29788c2ecf20Sopenharmony_ci prod_rx_pg->page = cons_rx_pg->page; 29798c2ecf20Sopenharmony_ci cons_rx_pg->page = NULL; 29808c2ecf20Sopenharmony_ci dma_unmap_addr_set(prod_rx_pg, mapping, 29818c2ecf20Sopenharmony_ci dma_unmap_addr(cons_rx_pg, mapping)); 29828c2ecf20Sopenharmony_ci 29838c2ecf20Sopenharmony_ci prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi; 29848c2ecf20Sopenharmony_ci prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo; 29858c2ecf20Sopenharmony_ci 29868c2ecf20Sopenharmony_ci } 29878c2ecf20Sopenharmony_ci cons = BNX2_RX_PG_RING_IDX(BNX2_NEXT_RX_BD(cons)); 29888c2ecf20Sopenharmony_ci hw_prod = BNX2_NEXT_RX_BD(hw_prod); 29898c2ecf20Sopenharmony_ci } 29908c2ecf20Sopenharmony_ci rxr->rx_pg_prod = hw_prod; 29918c2ecf20Sopenharmony_ci rxr->rx_pg_cons = cons; 29928c2ecf20Sopenharmony_ci} 29938c2ecf20Sopenharmony_ci 29948c2ecf20Sopenharmony_cistatic inline void 29958c2ecf20Sopenharmony_cibnx2_reuse_rx_data(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, 29968c2ecf20Sopenharmony_ci u8 *data, u16 cons, u16 prod) 29978c2ecf20Sopenharmony_ci{ 29988c2ecf20Sopenharmony_ci struct bnx2_sw_bd *cons_rx_buf, *prod_rx_buf; 29998c2ecf20Sopenharmony_ci struct bnx2_rx_bd *cons_bd, *prod_bd; 30008c2ecf20Sopenharmony_ci 30018c2ecf20Sopenharmony_ci cons_rx_buf = &rxr->rx_buf_ring[cons]; 30028c2ecf20Sopenharmony_ci prod_rx_buf = &rxr->rx_buf_ring[prod]; 30038c2ecf20Sopenharmony_ci 30048c2ecf20Sopenharmony_ci dma_sync_single_for_device(&bp->pdev->dev, 30058c2ecf20Sopenharmony_ci dma_unmap_addr(cons_rx_buf, mapping), 30068c2ecf20Sopenharmony_ci BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH, PCI_DMA_FROMDEVICE); 30078c2ecf20Sopenharmony_ci 30088c2ecf20Sopenharmony_ci rxr->rx_prod_bseq += bp->rx_buf_use_size; 30098c2ecf20Sopenharmony_ci 30108c2ecf20Sopenharmony_ci prod_rx_buf->data = data; 30118c2ecf20Sopenharmony_ci 30128c2ecf20Sopenharmony_ci if (cons == prod) 30138c2ecf20Sopenharmony_ci return; 30148c2ecf20Sopenharmony_ci 30158c2ecf20Sopenharmony_ci dma_unmap_addr_set(prod_rx_buf, mapping, 30168c2ecf20Sopenharmony_ci dma_unmap_addr(cons_rx_buf, mapping)); 30178c2ecf20Sopenharmony_ci 30188c2ecf20Sopenharmony_ci cons_bd = &rxr->rx_desc_ring[BNX2_RX_RING(cons)][BNX2_RX_IDX(cons)]; 30198c2ecf20Sopenharmony_ci prod_bd = &rxr->rx_desc_ring[BNX2_RX_RING(prod)][BNX2_RX_IDX(prod)]; 30208c2ecf20Sopenharmony_ci prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi; 30218c2ecf20Sopenharmony_ci prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo; 30228c2ecf20Sopenharmony_ci} 30238c2ecf20Sopenharmony_ci 30248c2ecf20Sopenharmony_cistatic struct sk_buff * 30258c2ecf20Sopenharmony_cibnx2_rx_skb(struct bnx2 *bp, struct bnx2_rx_ring_info *rxr, u8 *data, 30268c2ecf20Sopenharmony_ci unsigned int len, unsigned int hdr_len, dma_addr_t dma_addr, 30278c2ecf20Sopenharmony_ci u32 ring_idx) 30288c2ecf20Sopenharmony_ci{ 30298c2ecf20Sopenharmony_ci int err; 30308c2ecf20Sopenharmony_ci u16 prod = ring_idx & 0xffff; 30318c2ecf20Sopenharmony_ci struct sk_buff *skb; 30328c2ecf20Sopenharmony_ci 30338c2ecf20Sopenharmony_ci err = bnx2_alloc_rx_data(bp, rxr, prod, GFP_ATOMIC); 30348c2ecf20Sopenharmony_ci if (unlikely(err)) { 30358c2ecf20Sopenharmony_ci bnx2_reuse_rx_data(bp, rxr, data, (u16) (ring_idx >> 16), prod); 30368c2ecf20Sopenharmony_cierror: 30378c2ecf20Sopenharmony_ci if (hdr_len) { 30388c2ecf20Sopenharmony_ci unsigned int raw_len = len + 4; 30398c2ecf20Sopenharmony_ci int pages = PAGE_ALIGN(raw_len - hdr_len) >> PAGE_SHIFT; 30408c2ecf20Sopenharmony_ci 30418c2ecf20Sopenharmony_ci bnx2_reuse_rx_skb_pages(bp, rxr, NULL, pages); 30428c2ecf20Sopenharmony_ci } 30438c2ecf20Sopenharmony_ci return NULL; 30448c2ecf20Sopenharmony_ci } 30458c2ecf20Sopenharmony_ci 30468c2ecf20Sopenharmony_ci dma_unmap_single(&bp->pdev->dev, dma_addr, bp->rx_buf_use_size, 30478c2ecf20Sopenharmony_ci PCI_DMA_FROMDEVICE); 30488c2ecf20Sopenharmony_ci skb = build_skb(data, 0); 30498c2ecf20Sopenharmony_ci if (!skb) { 30508c2ecf20Sopenharmony_ci kfree(data); 30518c2ecf20Sopenharmony_ci goto error; 30528c2ecf20Sopenharmony_ci } 30538c2ecf20Sopenharmony_ci skb_reserve(skb, ((u8 *)get_l2_fhdr(data) - data) + BNX2_RX_OFFSET); 30548c2ecf20Sopenharmony_ci if (hdr_len == 0) { 30558c2ecf20Sopenharmony_ci skb_put(skb, len); 30568c2ecf20Sopenharmony_ci return skb; 30578c2ecf20Sopenharmony_ci } else { 30588c2ecf20Sopenharmony_ci unsigned int i, frag_len, frag_size, pages; 30598c2ecf20Sopenharmony_ci struct bnx2_sw_pg *rx_pg; 30608c2ecf20Sopenharmony_ci u16 pg_cons = rxr->rx_pg_cons; 30618c2ecf20Sopenharmony_ci u16 pg_prod = rxr->rx_pg_prod; 30628c2ecf20Sopenharmony_ci 30638c2ecf20Sopenharmony_ci frag_size = len + 4 - hdr_len; 30648c2ecf20Sopenharmony_ci pages = PAGE_ALIGN(frag_size) >> PAGE_SHIFT; 30658c2ecf20Sopenharmony_ci skb_put(skb, hdr_len); 30668c2ecf20Sopenharmony_ci 30678c2ecf20Sopenharmony_ci for (i = 0; i < pages; i++) { 30688c2ecf20Sopenharmony_ci dma_addr_t mapping_old; 30698c2ecf20Sopenharmony_ci 30708c2ecf20Sopenharmony_ci frag_len = min(frag_size, (unsigned int) PAGE_SIZE); 30718c2ecf20Sopenharmony_ci if (unlikely(frag_len <= 4)) { 30728c2ecf20Sopenharmony_ci unsigned int tail = 4 - frag_len; 30738c2ecf20Sopenharmony_ci 30748c2ecf20Sopenharmony_ci rxr->rx_pg_cons = pg_cons; 30758c2ecf20Sopenharmony_ci rxr->rx_pg_prod = pg_prod; 30768c2ecf20Sopenharmony_ci bnx2_reuse_rx_skb_pages(bp, rxr, NULL, 30778c2ecf20Sopenharmony_ci pages - i); 30788c2ecf20Sopenharmony_ci skb->len -= tail; 30798c2ecf20Sopenharmony_ci if (i == 0) { 30808c2ecf20Sopenharmony_ci skb->tail -= tail; 30818c2ecf20Sopenharmony_ci } else { 30828c2ecf20Sopenharmony_ci skb_frag_t *frag = 30838c2ecf20Sopenharmony_ci &skb_shinfo(skb)->frags[i - 1]; 30848c2ecf20Sopenharmony_ci skb_frag_size_sub(frag, tail); 30858c2ecf20Sopenharmony_ci skb->data_len -= tail; 30868c2ecf20Sopenharmony_ci } 30878c2ecf20Sopenharmony_ci return skb; 30888c2ecf20Sopenharmony_ci } 30898c2ecf20Sopenharmony_ci rx_pg = &rxr->rx_pg_ring[pg_cons]; 30908c2ecf20Sopenharmony_ci 30918c2ecf20Sopenharmony_ci /* Don't unmap yet. If we're unable to allocate a new 30928c2ecf20Sopenharmony_ci * page, we need to recycle the page and the DMA addr. 30938c2ecf20Sopenharmony_ci */ 30948c2ecf20Sopenharmony_ci mapping_old = dma_unmap_addr(rx_pg, mapping); 30958c2ecf20Sopenharmony_ci if (i == pages - 1) 30968c2ecf20Sopenharmony_ci frag_len -= 4; 30978c2ecf20Sopenharmony_ci 30988c2ecf20Sopenharmony_ci skb_fill_page_desc(skb, i, rx_pg->page, 0, frag_len); 30998c2ecf20Sopenharmony_ci rx_pg->page = NULL; 31008c2ecf20Sopenharmony_ci 31018c2ecf20Sopenharmony_ci err = bnx2_alloc_rx_page(bp, rxr, 31028c2ecf20Sopenharmony_ci BNX2_RX_PG_RING_IDX(pg_prod), 31038c2ecf20Sopenharmony_ci GFP_ATOMIC); 31048c2ecf20Sopenharmony_ci if (unlikely(err)) { 31058c2ecf20Sopenharmony_ci rxr->rx_pg_cons = pg_cons; 31068c2ecf20Sopenharmony_ci rxr->rx_pg_prod = pg_prod; 31078c2ecf20Sopenharmony_ci bnx2_reuse_rx_skb_pages(bp, rxr, skb, 31088c2ecf20Sopenharmony_ci pages - i); 31098c2ecf20Sopenharmony_ci return NULL; 31108c2ecf20Sopenharmony_ci } 31118c2ecf20Sopenharmony_ci 31128c2ecf20Sopenharmony_ci dma_unmap_page(&bp->pdev->dev, mapping_old, 31138c2ecf20Sopenharmony_ci PAGE_SIZE, PCI_DMA_FROMDEVICE); 31148c2ecf20Sopenharmony_ci 31158c2ecf20Sopenharmony_ci frag_size -= frag_len; 31168c2ecf20Sopenharmony_ci skb->data_len += frag_len; 31178c2ecf20Sopenharmony_ci skb->truesize += PAGE_SIZE; 31188c2ecf20Sopenharmony_ci skb->len += frag_len; 31198c2ecf20Sopenharmony_ci 31208c2ecf20Sopenharmony_ci pg_prod = BNX2_NEXT_RX_BD(pg_prod); 31218c2ecf20Sopenharmony_ci pg_cons = BNX2_RX_PG_RING_IDX(BNX2_NEXT_RX_BD(pg_cons)); 31228c2ecf20Sopenharmony_ci } 31238c2ecf20Sopenharmony_ci rxr->rx_pg_prod = pg_prod; 31248c2ecf20Sopenharmony_ci rxr->rx_pg_cons = pg_cons; 31258c2ecf20Sopenharmony_ci } 31268c2ecf20Sopenharmony_ci return skb; 31278c2ecf20Sopenharmony_ci} 31288c2ecf20Sopenharmony_ci 31298c2ecf20Sopenharmony_cistatic inline u16 31308c2ecf20Sopenharmony_cibnx2_get_hw_rx_cons(struct bnx2_napi *bnapi) 31318c2ecf20Sopenharmony_ci{ 31328c2ecf20Sopenharmony_ci u16 cons; 31338c2ecf20Sopenharmony_ci 31348c2ecf20Sopenharmony_ci cons = READ_ONCE(*bnapi->hw_rx_cons_ptr); 31358c2ecf20Sopenharmony_ci 31368c2ecf20Sopenharmony_ci if (unlikely((cons & BNX2_MAX_RX_DESC_CNT) == BNX2_MAX_RX_DESC_CNT)) 31378c2ecf20Sopenharmony_ci cons++; 31388c2ecf20Sopenharmony_ci return cons; 31398c2ecf20Sopenharmony_ci} 31408c2ecf20Sopenharmony_ci 31418c2ecf20Sopenharmony_cistatic int 31428c2ecf20Sopenharmony_cibnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) 31438c2ecf20Sopenharmony_ci{ 31448c2ecf20Sopenharmony_ci struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring; 31458c2ecf20Sopenharmony_ci u16 hw_cons, sw_cons, sw_ring_cons, sw_prod, sw_ring_prod; 31468c2ecf20Sopenharmony_ci struct l2_fhdr *rx_hdr; 31478c2ecf20Sopenharmony_ci int rx_pkt = 0, pg_ring_used = 0; 31488c2ecf20Sopenharmony_ci 31498c2ecf20Sopenharmony_ci if (budget <= 0) 31508c2ecf20Sopenharmony_ci return rx_pkt; 31518c2ecf20Sopenharmony_ci 31528c2ecf20Sopenharmony_ci hw_cons = bnx2_get_hw_rx_cons(bnapi); 31538c2ecf20Sopenharmony_ci sw_cons = rxr->rx_cons; 31548c2ecf20Sopenharmony_ci sw_prod = rxr->rx_prod; 31558c2ecf20Sopenharmony_ci 31568c2ecf20Sopenharmony_ci /* Memory barrier necessary as speculative reads of the rx 31578c2ecf20Sopenharmony_ci * buffer can be ahead of the index in the status block 31588c2ecf20Sopenharmony_ci */ 31598c2ecf20Sopenharmony_ci rmb(); 31608c2ecf20Sopenharmony_ci while (sw_cons != hw_cons) { 31618c2ecf20Sopenharmony_ci unsigned int len, hdr_len; 31628c2ecf20Sopenharmony_ci u32 status; 31638c2ecf20Sopenharmony_ci struct bnx2_sw_bd *rx_buf, *next_rx_buf; 31648c2ecf20Sopenharmony_ci struct sk_buff *skb; 31658c2ecf20Sopenharmony_ci dma_addr_t dma_addr; 31668c2ecf20Sopenharmony_ci u8 *data; 31678c2ecf20Sopenharmony_ci u16 next_ring_idx; 31688c2ecf20Sopenharmony_ci 31698c2ecf20Sopenharmony_ci sw_ring_cons = BNX2_RX_RING_IDX(sw_cons); 31708c2ecf20Sopenharmony_ci sw_ring_prod = BNX2_RX_RING_IDX(sw_prod); 31718c2ecf20Sopenharmony_ci 31728c2ecf20Sopenharmony_ci rx_buf = &rxr->rx_buf_ring[sw_ring_cons]; 31738c2ecf20Sopenharmony_ci data = rx_buf->data; 31748c2ecf20Sopenharmony_ci rx_buf->data = NULL; 31758c2ecf20Sopenharmony_ci 31768c2ecf20Sopenharmony_ci rx_hdr = get_l2_fhdr(data); 31778c2ecf20Sopenharmony_ci prefetch(rx_hdr); 31788c2ecf20Sopenharmony_ci 31798c2ecf20Sopenharmony_ci dma_addr = dma_unmap_addr(rx_buf, mapping); 31808c2ecf20Sopenharmony_ci 31818c2ecf20Sopenharmony_ci dma_sync_single_for_cpu(&bp->pdev->dev, dma_addr, 31828c2ecf20Sopenharmony_ci BNX2_RX_OFFSET + BNX2_RX_COPY_THRESH, 31838c2ecf20Sopenharmony_ci PCI_DMA_FROMDEVICE); 31848c2ecf20Sopenharmony_ci 31858c2ecf20Sopenharmony_ci next_ring_idx = BNX2_RX_RING_IDX(BNX2_NEXT_RX_BD(sw_cons)); 31868c2ecf20Sopenharmony_ci next_rx_buf = &rxr->rx_buf_ring[next_ring_idx]; 31878c2ecf20Sopenharmony_ci prefetch(get_l2_fhdr(next_rx_buf->data)); 31888c2ecf20Sopenharmony_ci 31898c2ecf20Sopenharmony_ci len = rx_hdr->l2_fhdr_pkt_len; 31908c2ecf20Sopenharmony_ci status = rx_hdr->l2_fhdr_status; 31918c2ecf20Sopenharmony_ci 31928c2ecf20Sopenharmony_ci hdr_len = 0; 31938c2ecf20Sopenharmony_ci if (status & L2_FHDR_STATUS_SPLIT) { 31948c2ecf20Sopenharmony_ci hdr_len = rx_hdr->l2_fhdr_ip_xsum; 31958c2ecf20Sopenharmony_ci pg_ring_used = 1; 31968c2ecf20Sopenharmony_ci } else if (len > bp->rx_jumbo_thresh) { 31978c2ecf20Sopenharmony_ci hdr_len = bp->rx_jumbo_thresh; 31988c2ecf20Sopenharmony_ci pg_ring_used = 1; 31998c2ecf20Sopenharmony_ci } 32008c2ecf20Sopenharmony_ci 32018c2ecf20Sopenharmony_ci if (unlikely(status & (L2_FHDR_ERRORS_BAD_CRC | 32028c2ecf20Sopenharmony_ci L2_FHDR_ERRORS_PHY_DECODE | 32038c2ecf20Sopenharmony_ci L2_FHDR_ERRORS_ALIGNMENT | 32048c2ecf20Sopenharmony_ci L2_FHDR_ERRORS_TOO_SHORT | 32058c2ecf20Sopenharmony_ci L2_FHDR_ERRORS_GIANT_FRAME))) { 32068c2ecf20Sopenharmony_ci 32078c2ecf20Sopenharmony_ci bnx2_reuse_rx_data(bp, rxr, data, sw_ring_cons, 32088c2ecf20Sopenharmony_ci sw_ring_prod); 32098c2ecf20Sopenharmony_ci if (pg_ring_used) { 32108c2ecf20Sopenharmony_ci int pages; 32118c2ecf20Sopenharmony_ci 32128c2ecf20Sopenharmony_ci pages = PAGE_ALIGN(len - hdr_len) >> PAGE_SHIFT; 32138c2ecf20Sopenharmony_ci 32148c2ecf20Sopenharmony_ci bnx2_reuse_rx_skb_pages(bp, rxr, NULL, pages); 32158c2ecf20Sopenharmony_ci } 32168c2ecf20Sopenharmony_ci goto next_rx; 32178c2ecf20Sopenharmony_ci } 32188c2ecf20Sopenharmony_ci 32198c2ecf20Sopenharmony_ci len -= 4; 32208c2ecf20Sopenharmony_ci 32218c2ecf20Sopenharmony_ci if (len <= bp->rx_copy_thresh) { 32228c2ecf20Sopenharmony_ci skb = netdev_alloc_skb(bp->dev, len + 6); 32238c2ecf20Sopenharmony_ci if (!skb) { 32248c2ecf20Sopenharmony_ci bnx2_reuse_rx_data(bp, rxr, data, sw_ring_cons, 32258c2ecf20Sopenharmony_ci sw_ring_prod); 32268c2ecf20Sopenharmony_ci goto next_rx; 32278c2ecf20Sopenharmony_ci } 32288c2ecf20Sopenharmony_ci 32298c2ecf20Sopenharmony_ci /* aligned copy */ 32308c2ecf20Sopenharmony_ci memcpy(skb->data, 32318c2ecf20Sopenharmony_ci (u8 *)rx_hdr + BNX2_RX_OFFSET - 6, 32328c2ecf20Sopenharmony_ci len + 6); 32338c2ecf20Sopenharmony_ci skb_reserve(skb, 6); 32348c2ecf20Sopenharmony_ci skb_put(skb, len); 32358c2ecf20Sopenharmony_ci 32368c2ecf20Sopenharmony_ci bnx2_reuse_rx_data(bp, rxr, data, 32378c2ecf20Sopenharmony_ci sw_ring_cons, sw_ring_prod); 32388c2ecf20Sopenharmony_ci 32398c2ecf20Sopenharmony_ci } else { 32408c2ecf20Sopenharmony_ci skb = bnx2_rx_skb(bp, rxr, data, len, hdr_len, dma_addr, 32418c2ecf20Sopenharmony_ci (sw_ring_cons << 16) | sw_ring_prod); 32428c2ecf20Sopenharmony_ci if (!skb) 32438c2ecf20Sopenharmony_ci goto next_rx; 32448c2ecf20Sopenharmony_ci } 32458c2ecf20Sopenharmony_ci if ((status & L2_FHDR_STATUS_L2_VLAN_TAG) && 32468c2ecf20Sopenharmony_ci !(bp->rx_mode & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG)) 32478c2ecf20Sopenharmony_ci __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), rx_hdr->l2_fhdr_vlan_tag); 32488c2ecf20Sopenharmony_ci 32498c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, bp->dev); 32508c2ecf20Sopenharmony_ci 32518c2ecf20Sopenharmony_ci if (len > (bp->dev->mtu + ETH_HLEN) && 32528c2ecf20Sopenharmony_ci skb->protocol != htons(0x8100) && 32538c2ecf20Sopenharmony_ci skb->protocol != htons(ETH_P_8021AD)) { 32548c2ecf20Sopenharmony_ci 32558c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 32568c2ecf20Sopenharmony_ci goto next_rx; 32578c2ecf20Sopenharmony_ci 32588c2ecf20Sopenharmony_ci } 32598c2ecf20Sopenharmony_ci 32608c2ecf20Sopenharmony_ci skb_checksum_none_assert(skb); 32618c2ecf20Sopenharmony_ci if ((bp->dev->features & NETIF_F_RXCSUM) && 32628c2ecf20Sopenharmony_ci (status & (L2_FHDR_STATUS_TCP_SEGMENT | 32638c2ecf20Sopenharmony_ci L2_FHDR_STATUS_UDP_DATAGRAM))) { 32648c2ecf20Sopenharmony_ci 32658c2ecf20Sopenharmony_ci if (likely((status & (L2_FHDR_ERRORS_TCP_XSUM | 32668c2ecf20Sopenharmony_ci L2_FHDR_ERRORS_UDP_XSUM)) == 0)) 32678c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 32688c2ecf20Sopenharmony_ci } 32698c2ecf20Sopenharmony_ci if ((bp->dev->features & NETIF_F_RXHASH) && 32708c2ecf20Sopenharmony_ci ((status & L2_FHDR_STATUS_USE_RXHASH) == 32718c2ecf20Sopenharmony_ci L2_FHDR_STATUS_USE_RXHASH)) 32728c2ecf20Sopenharmony_ci skb_set_hash(skb, rx_hdr->l2_fhdr_hash, 32738c2ecf20Sopenharmony_ci PKT_HASH_TYPE_L3); 32748c2ecf20Sopenharmony_ci 32758c2ecf20Sopenharmony_ci skb_record_rx_queue(skb, bnapi - &bp->bnx2_napi[0]); 32768c2ecf20Sopenharmony_ci napi_gro_receive(&bnapi->napi, skb); 32778c2ecf20Sopenharmony_ci rx_pkt++; 32788c2ecf20Sopenharmony_ci 32798c2ecf20Sopenharmony_cinext_rx: 32808c2ecf20Sopenharmony_ci sw_cons = BNX2_NEXT_RX_BD(sw_cons); 32818c2ecf20Sopenharmony_ci sw_prod = BNX2_NEXT_RX_BD(sw_prod); 32828c2ecf20Sopenharmony_ci 32838c2ecf20Sopenharmony_ci if (rx_pkt == budget) 32848c2ecf20Sopenharmony_ci break; 32858c2ecf20Sopenharmony_ci 32868c2ecf20Sopenharmony_ci /* Refresh hw_cons to see if there is new work */ 32878c2ecf20Sopenharmony_ci if (sw_cons == hw_cons) { 32888c2ecf20Sopenharmony_ci hw_cons = bnx2_get_hw_rx_cons(bnapi); 32898c2ecf20Sopenharmony_ci rmb(); 32908c2ecf20Sopenharmony_ci } 32918c2ecf20Sopenharmony_ci } 32928c2ecf20Sopenharmony_ci rxr->rx_cons = sw_cons; 32938c2ecf20Sopenharmony_ci rxr->rx_prod = sw_prod; 32948c2ecf20Sopenharmony_ci 32958c2ecf20Sopenharmony_ci if (pg_ring_used) 32968c2ecf20Sopenharmony_ci BNX2_WR16(bp, rxr->rx_pg_bidx_addr, rxr->rx_pg_prod); 32978c2ecf20Sopenharmony_ci 32988c2ecf20Sopenharmony_ci BNX2_WR16(bp, rxr->rx_bidx_addr, sw_prod); 32998c2ecf20Sopenharmony_ci 33008c2ecf20Sopenharmony_ci BNX2_WR(bp, rxr->rx_bseq_addr, rxr->rx_prod_bseq); 33018c2ecf20Sopenharmony_ci 33028c2ecf20Sopenharmony_ci return rx_pkt; 33038c2ecf20Sopenharmony_ci 33048c2ecf20Sopenharmony_ci} 33058c2ecf20Sopenharmony_ci 33068c2ecf20Sopenharmony_ci/* MSI ISR - The only difference between this and the INTx ISR 33078c2ecf20Sopenharmony_ci * is that the MSI interrupt is always serviced. 33088c2ecf20Sopenharmony_ci */ 33098c2ecf20Sopenharmony_cistatic irqreturn_t 33108c2ecf20Sopenharmony_cibnx2_msi(int irq, void *dev_instance) 33118c2ecf20Sopenharmony_ci{ 33128c2ecf20Sopenharmony_ci struct bnx2_napi *bnapi = dev_instance; 33138c2ecf20Sopenharmony_ci struct bnx2 *bp = bnapi->bp; 33148c2ecf20Sopenharmony_ci 33158c2ecf20Sopenharmony_ci prefetch(bnapi->status_blk.msi); 33168c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, 33178c2ecf20Sopenharmony_ci BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM | 33188c2ecf20Sopenharmony_ci BNX2_PCICFG_INT_ACK_CMD_MASK_INT); 33198c2ecf20Sopenharmony_ci 33208c2ecf20Sopenharmony_ci /* Return here if interrupt is disabled. */ 33218c2ecf20Sopenharmony_ci if (unlikely(atomic_read(&bp->intr_sem) != 0)) 33228c2ecf20Sopenharmony_ci return IRQ_HANDLED; 33238c2ecf20Sopenharmony_ci 33248c2ecf20Sopenharmony_ci napi_schedule(&bnapi->napi); 33258c2ecf20Sopenharmony_ci 33268c2ecf20Sopenharmony_ci return IRQ_HANDLED; 33278c2ecf20Sopenharmony_ci} 33288c2ecf20Sopenharmony_ci 33298c2ecf20Sopenharmony_cistatic irqreturn_t 33308c2ecf20Sopenharmony_cibnx2_msi_1shot(int irq, void *dev_instance) 33318c2ecf20Sopenharmony_ci{ 33328c2ecf20Sopenharmony_ci struct bnx2_napi *bnapi = dev_instance; 33338c2ecf20Sopenharmony_ci struct bnx2 *bp = bnapi->bp; 33348c2ecf20Sopenharmony_ci 33358c2ecf20Sopenharmony_ci prefetch(bnapi->status_blk.msi); 33368c2ecf20Sopenharmony_ci 33378c2ecf20Sopenharmony_ci /* Return here if interrupt is disabled. */ 33388c2ecf20Sopenharmony_ci if (unlikely(atomic_read(&bp->intr_sem) != 0)) 33398c2ecf20Sopenharmony_ci return IRQ_HANDLED; 33408c2ecf20Sopenharmony_ci 33418c2ecf20Sopenharmony_ci napi_schedule(&bnapi->napi); 33428c2ecf20Sopenharmony_ci 33438c2ecf20Sopenharmony_ci return IRQ_HANDLED; 33448c2ecf20Sopenharmony_ci} 33458c2ecf20Sopenharmony_ci 33468c2ecf20Sopenharmony_cistatic irqreturn_t 33478c2ecf20Sopenharmony_cibnx2_interrupt(int irq, void *dev_instance) 33488c2ecf20Sopenharmony_ci{ 33498c2ecf20Sopenharmony_ci struct bnx2_napi *bnapi = dev_instance; 33508c2ecf20Sopenharmony_ci struct bnx2 *bp = bnapi->bp; 33518c2ecf20Sopenharmony_ci struct status_block *sblk = bnapi->status_blk.msi; 33528c2ecf20Sopenharmony_ci 33538c2ecf20Sopenharmony_ci /* When using INTx, it is possible for the interrupt to arrive 33548c2ecf20Sopenharmony_ci * at the CPU before the status block posted prior to the 33558c2ecf20Sopenharmony_ci * interrupt. Reading a register will flush the status block. 33568c2ecf20Sopenharmony_ci * When using MSI, the MSI message will always complete after 33578c2ecf20Sopenharmony_ci * the status block write. 33588c2ecf20Sopenharmony_ci */ 33598c2ecf20Sopenharmony_ci if ((sblk->status_idx == bnapi->last_status_idx) && 33608c2ecf20Sopenharmony_ci (BNX2_RD(bp, BNX2_PCICFG_MISC_STATUS) & 33618c2ecf20Sopenharmony_ci BNX2_PCICFG_MISC_STATUS_INTA_VALUE)) 33628c2ecf20Sopenharmony_ci return IRQ_NONE; 33638c2ecf20Sopenharmony_ci 33648c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, 33658c2ecf20Sopenharmony_ci BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM | 33668c2ecf20Sopenharmony_ci BNX2_PCICFG_INT_ACK_CMD_MASK_INT); 33678c2ecf20Sopenharmony_ci 33688c2ecf20Sopenharmony_ci /* Read back to deassert IRQ immediately to avoid too many 33698c2ecf20Sopenharmony_ci * spurious interrupts. 33708c2ecf20Sopenharmony_ci */ 33718c2ecf20Sopenharmony_ci BNX2_RD(bp, BNX2_PCICFG_INT_ACK_CMD); 33728c2ecf20Sopenharmony_ci 33738c2ecf20Sopenharmony_ci /* Return here if interrupt is shared and is disabled. */ 33748c2ecf20Sopenharmony_ci if (unlikely(atomic_read(&bp->intr_sem) != 0)) 33758c2ecf20Sopenharmony_ci return IRQ_HANDLED; 33768c2ecf20Sopenharmony_ci 33778c2ecf20Sopenharmony_ci if (napi_schedule_prep(&bnapi->napi)) { 33788c2ecf20Sopenharmony_ci bnapi->last_status_idx = sblk->status_idx; 33798c2ecf20Sopenharmony_ci __napi_schedule(&bnapi->napi); 33808c2ecf20Sopenharmony_ci } 33818c2ecf20Sopenharmony_ci 33828c2ecf20Sopenharmony_ci return IRQ_HANDLED; 33838c2ecf20Sopenharmony_ci} 33848c2ecf20Sopenharmony_ci 33858c2ecf20Sopenharmony_cistatic inline int 33868c2ecf20Sopenharmony_cibnx2_has_fast_work(struct bnx2_napi *bnapi) 33878c2ecf20Sopenharmony_ci{ 33888c2ecf20Sopenharmony_ci struct bnx2_tx_ring_info *txr = &bnapi->tx_ring; 33898c2ecf20Sopenharmony_ci struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring; 33908c2ecf20Sopenharmony_ci 33918c2ecf20Sopenharmony_ci if ((bnx2_get_hw_rx_cons(bnapi) != rxr->rx_cons) || 33928c2ecf20Sopenharmony_ci (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons)) 33938c2ecf20Sopenharmony_ci return 1; 33948c2ecf20Sopenharmony_ci return 0; 33958c2ecf20Sopenharmony_ci} 33968c2ecf20Sopenharmony_ci 33978c2ecf20Sopenharmony_ci#define STATUS_ATTN_EVENTS (STATUS_ATTN_BITS_LINK_STATE | \ 33988c2ecf20Sopenharmony_ci STATUS_ATTN_BITS_TIMER_ABORT) 33998c2ecf20Sopenharmony_ci 34008c2ecf20Sopenharmony_cistatic inline int 34018c2ecf20Sopenharmony_cibnx2_has_work(struct bnx2_napi *bnapi) 34028c2ecf20Sopenharmony_ci{ 34038c2ecf20Sopenharmony_ci struct status_block *sblk = bnapi->status_blk.msi; 34048c2ecf20Sopenharmony_ci 34058c2ecf20Sopenharmony_ci if (bnx2_has_fast_work(bnapi)) 34068c2ecf20Sopenharmony_ci return 1; 34078c2ecf20Sopenharmony_ci 34088c2ecf20Sopenharmony_ci#ifdef BCM_CNIC 34098c2ecf20Sopenharmony_ci if (bnapi->cnic_present && (bnapi->cnic_tag != sblk->status_idx)) 34108c2ecf20Sopenharmony_ci return 1; 34118c2ecf20Sopenharmony_ci#endif 34128c2ecf20Sopenharmony_ci 34138c2ecf20Sopenharmony_ci if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) != 34148c2ecf20Sopenharmony_ci (sblk->status_attn_bits_ack & STATUS_ATTN_EVENTS)) 34158c2ecf20Sopenharmony_ci return 1; 34168c2ecf20Sopenharmony_ci 34178c2ecf20Sopenharmony_ci return 0; 34188c2ecf20Sopenharmony_ci} 34198c2ecf20Sopenharmony_ci 34208c2ecf20Sopenharmony_cistatic void 34218c2ecf20Sopenharmony_cibnx2_chk_missed_msi(struct bnx2 *bp) 34228c2ecf20Sopenharmony_ci{ 34238c2ecf20Sopenharmony_ci struct bnx2_napi *bnapi = &bp->bnx2_napi[0]; 34248c2ecf20Sopenharmony_ci u32 msi_ctrl; 34258c2ecf20Sopenharmony_ci 34268c2ecf20Sopenharmony_ci if (bnx2_has_work(bnapi)) { 34278c2ecf20Sopenharmony_ci msi_ctrl = BNX2_RD(bp, BNX2_PCICFG_MSI_CONTROL); 34288c2ecf20Sopenharmony_ci if (!(msi_ctrl & BNX2_PCICFG_MSI_CONTROL_ENABLE)) 34298c2ecf20Sopenharmony_ci return; 34308c2ecf20Sopenharmony_ci 34318c2ecf20Sopenharmony_ci if (bnapi->last_status_idx == bp->idle_chk_status_idx) { 34328c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_PCICFG_MSI_CONTROL, msi_ctrl & 34338c2ecf20Sopenharmony_ci ~BNX2_PCICFG_MSI_CONTROL_ENABLE); 34348c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_PCICFG_MSI_CONTROL, msi_ctrl); 34358c2ecf20Sopenharmony_ci bnx2_msi(bp->irq_tbl[0].vector, bnapi); 34368c2ecf20Sopenharmony_ci } 34378c2ecf20Sopenharmony_ci } 34388c2ecf20Sopenharmony_ci 34398c2ecf20Sopenharmony_ci bp->idle_chk_status_idx = bnapi->last_status_idx; 34408c2ecf20Sopenharmony_ci} 34418c2ecf20Sopenharmony_ci 34428c2ecf20Sopenharmony_ci#ifdef BCM_CNIC 34438c2ecf20Sopenharmony_cistatic void bnx2_poll_cnic(struct bnx2 *bp, struct bnx2_napi *bnapi) 34448c2ecf20Sopenharmony_ci{ 34458c2ecf20Sopenharmony_ci struct cnic_ops *c_ops; 34468c2ecf20Sopenharmony_ci 34478c2ecf20Sopenharmony_ci if (!bnapi->cnic_present) 34488c2ecf20Sopenharmony_ci return; 34498c2ecf20Sopenharmony_ci 34508c2ecf20Sopenharmony_ci rcu_read_lock(); 34518c2ecf20Sopenharmony_ci c_ops = rcu_dereference(bp->cnic_ops); 34528c2ecf20Sopenharmony_ci if (c_ops) 34538c2ecf20Sopenharmony_ci bnapi->cnic_tag = c_ops->cnic_handler(bp->cnic_data, 34548c2ecf20Sopenharmony_ci bnapi->status_blk.msi); 34558c2ecf20Sopenharmony_ci rcu_read_unlock(); 34568c2ecf20Sopenharmony_ci} 34578c2ecf20Sopenharmony_ci#endif 34588c2ecf20Sopenharmony_ci 34598c2ecf20Sopenharmony_cistatic void bnx2_poll_link(struct bnx2 *bp, struct bnx2_napi *bnapi) 34608c2ecf20Sopenharmony_ci{ 34618c2ecf20Sopenharmony_ci struct status_block *sblk = bnapi->status_blk.msi; 34628c2ecf20Sopenharmony_ci u32 status_attn_bits = sblk->status_attn_bits; 34638c2ecf20Sopenharmony_ci u32 status_attn_bits_ack = sblk->status_attn_bits_ack; 34648c2ecf20Sopenharmony_ci 34658c2ecf20Sopenharmony_ci if ((status_attn_bits & STATUS_ATTN_EVENTS) != 34668c2ecf20Sopenharmony_ci (status_attn_bits_ack & STATUS_ATTN_EVENTS)) { 34678c2ecf20Sopenharmony_ci 34688c2ecf20Sopenharmony_ci bnx2_phy_int(bp, bnapi); 34698c2ecf20Sopenharmony_ci 34708c2ecf20Sopenharmony_ci /* This is needed to take care of transient status 34718c2ecf20Sopenharmony_ci * during link changes. 34728c2ecf20Sopenharmony_ci */ 34738c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_HC_COMMAND, 34748c2ecf20Sopenharmony_ci bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT); 34758c2ecf20Sopenharmony_ci BNX2_RD(bp, BNX2_HC_COMMAND); 34768c2ecf20Sopenharmony_ci } 34778c2ecf20Sopenharmony_ci} 34788c2ecf20Sopenharmony_ci 34798c2ecf20Sopenharmony_cistatic int bnx2_poll_work(struct bnx2 *bp, struct bnx2_napi *bnapi, 34808c2ecf20Sopenharmony_ci int work_done, int budget) 34818c2ecf20Sopenharmony_ci{ 34828c2ecf20Sopenharmony_ci struct bnx2_tx_ring_info *txr = &bnapi->tx_ring; 34838c2ecf20Sopenharmony_ci struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring; 34848c2ecf20Sopenharmony_ci 34858c2ecf20Sopenharmony_ci if (bnx2_get_hw_tx_cons(bnapi) != txr->hw_tx_cons) 34868c2ecf20Sopenharmony_ci bnx2_tx_int(bp, bnapi, 0); 34878c2ecf20Sopenharmony_ci 34888c2ecf20Sopenharmony_ci if (bnx2_get_hw_rx_cons(bnapi) != rxr->rx_cons) 34898c2ecf20Sopenharmony_ci work_done += bnx2_rx_int(bp, bnapi, budget - work_done); 34908c2ecf20Sopenharmony_ci 34918c2ecf20Sopenharmony_ci return work_done; 34928c2ecf20Sopenharmony_ci} 34938c2ecf20Sopenharmony_ci 34948c2ecf20Sopenharmony_cistatic int bnx2_poll_msix(struct napi_struct *napi, int budget) 34958c2ecf20Sopenharmony_ci{ 34968c2ecf20Sopenharmony_ci struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi); 34978c2ecf20Sopenharmony_ci struct bnx2 *bp = bnapi->bp; 34988c2ecf20Sopenharmony_ci int work_done = 0; 34998c2ecf20Sopenharmony_ci struct status_block_msix *sblk = bnapi->status_blk.msix; 35008c2ecf20Sopenharmony_ci 35018c2ecf20Sopenharmony_ci while (1) { 35028c2ecf20Sopenharmony_ci work_done = bnx2_poll_work(bp, bnapi, work_done, budget); 35038c2ecf20Sopenharmony_ci if (unlikely(work_done >= budget)) 35048c2ecf20Sopenharmony_ci break; 35058c2ecf20Sopenharmony_ci 35068c2ecf20Sopenharmony_ci bnapi->last_status_idx = sblk->status_idx; 35078c2ecf20Sopenharmony_ci /* status idx must be read before checking for more work. */ 35088c2ecf20Sopenharmony_ci rmb(); 35098c2ecf20Sopenharmony_ci if (likely(!bnx2_has_fast_work(bnapi))) { 35108c2ecf20Sopenharmony_ci 35118c2ecf20Sopenharmony_ci napi_complete_done(napi, work_done); 35128c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num | 35138c2ecf20Sopenharmony_ci BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | 35148c2ecf20Sopenharmony_ci bnapi->last_status_idx); 35158c2ecf20Sopenharmony_ci break; 35168c2ecf20Sopenharmony_ci } 35178c2ecf20Sopenharmony_ci } 35188c2ecf20Sopenharmony_ci return work_done; 35198c2ecf20Sopenharmony_ci} 35208c2ecf20Sopenharmony_ci 35218c2ecf20Sopenharmony_cistatic int bnx2_poll(struct napi_struct *napi, int budget) 35228c2ecf20Sopenharmony_ci{ 35238c2ecf20Sopenharmony_ci struct bnx2_napi *bnapi = container_of(napi, struct bnx2_napi, napi); 35248c2ecf20Sopenharmony_ci struct bnx2 *bp = bnapi->bp; 35258c2ecf20Sopenharmony_ci int work_done = 0; 35268c2ecf20Sopenharmony_ci struct status_block *sblk = bnapi->status_blk.msi; 35278c2ecf20Sopenharmony_ci 35288c2ecf20Sopenharmony_ci while (1) { 35298c2ecf20Sopenharmony_ci bnx2_poll_link(bp, bnapi); 35308c2ecf20Sopenharmony_ci 35318c2ecf20Sopenharmony_ci work_done = bnx2_poll_work(bp, bnapi, work_done, budget); 35328c2ecf20Sopenharmony_ci 35338c2ecf20Sopenharmony_ci#ifdef BCM_CNIC 35348c2ecf20Sopenharmony_ci bnx2_poll_cnic(bp, bnapi); 35358c2ecf20Sopenharmony_ci#endif 35368c2ecf20Sopenharmony_ci 35378c2ecf20Sopenharmony_ci /* bnapi->last_status_idx is used below to tell the hw how 35388c2ecf20Sopenharmony_ci * much work has been processed, so we must read it before 35398c2ecf20Sopenharmony_ci * checking for more work. 35408c2ecf20Sopenharmony_ci */ 35418c2ecf20Sopenharmony_ci bnapi->last_status_idx = sblk->status_idx; 35428c2ecf20Sopenharmony_ci 35438c2ecf20Sopenharmony_ci if (unlikely(work_done >= budget)) 35448c2ecf20Sopenharmony_ci break; 35458c2ecf20Sopenharmony_ci 35468c2ecf20Sopenharmony_ci rmb(); 35478c2ecf20Sopenharmony_ci if (likely(!bnx2_has_work(bnapi))) { 35488c2ecf20Sopenharmony_ci napi_complete_done(napi, work_done); 35498c2ecf20Sopenharmony_ci if (likely(bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)) { 35508c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, 35518c2ecf20Sopenharmony_ci BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | 35528c2ecf20Sopenharmony_ci bnapi->last_status_idx); 35538c2ecf20Sopenharmony_ci break; 35548c2ecf20Sopenharmony_ci } 35558c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, 35568c2ecf20Sopenharmony_ci BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | 35578c2ecf20Sopenharmony_ci BNX2_PCICFG_INT_ACK_CMD_MASK_INT | 35588c2ecf20Sopenharmony_ci bnapi->last_status_idx); 35598c2ecf20Sopenharmony_ci 35608c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, 35618c2ecf20Sopenharmony_ci BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | 35628c2ecf20Sopenharmony_ci bnapi->last_status_idx); 35638c2ecf20Sopenharmony_ci break; 35648c2ecf20Sopenharmony_ci } 35658c2ecf20Sopenharmony_ci } 35668c2ecf20Sopenharmony_ci 35678c2ecf20Sopenharmony_ci return work_done; 35688c2ecf20Sopenharmony_ci} 35698c2ecf20Sopenharmony_ci 35708c2ecf20Sopenharmony_ci/* Called with rtnl_lock from vlan functions and also netif_tx_lock 35718c2ecf20Sopenharmony_ci * from set_multicast. 35728c2ecf20Sopenharmony_ci */ 35738c2ecf20Sopenharmony_cistatic void 35748c2ecf20Sopenharmony_cibnx2_set_rx_mode(struct net_device *dev) 35758c2ecf20Sopenharmony_ci{ 35768c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 35778c2ecf20Sopenharmony_ci u32 rx_mode, sort_mode; 35788c2ecf20Sopenharmony_ci struct netdev_hw_addr *ha; 35798c2ecf20Sopenharmony_ci int i; 35808c2ecf20Sopenharmony_ci 35818c2ecf20Sopenharmony_ci if (!netif_running(dev)) 35828c2ecf20Sopenharmony_ci return; 35838c2ecf20Sopenharmony_ci 35848c2ecf20Sopenharmony_ci spin_lock_bh(&bp->phy_lock); 35858c2ecf20Sopenharmony_ci 35868c2ecf20Sopenharmony_ci rx_mode = bp->rx_mode & ~(BNX2_EMAC_RX_MODE_PROMISCUOUS | 35878c2ecf20Sopenharmony_ci BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG); 35888c2ecf20Sopenharmony_ci sort_mode = 1 | BNX2_RPM_SORT_USER0_BC_EN; 35898c2ecf20Sopenharmony_ci if (!(dev->features & NETIF_F_HW_VLAN_CTAG_RX) && 35908c2ecf20Sopenharmony_ci (bp->flags & BNX2_FLAG_CAN_KEEP_VLAN)) 35918c2ecf20Sopenharmony_ci rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG; 35928c2ecf20Sopenharmony_ci if (dev->flags & IFF_PROMISC) { 35938c2ecf20Sopenharmony_ci /* Promiscuous mode. */ 35948c2ecf20Sopenharmony_ci rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS; 35958c2ecf20Sopenharmony_ci sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN | 35968c2ecf20Sopenharmony_ci BNX2_RPM_SORT_USER0_PROM_VLAN; 35978c2ecf20Sopenharmony_ci } 35988c2ecf20Sopenharmony_ci else if (dev->flags & IFF_ALLMULTI) { 35998c2ecf20Sopenharmony_ci for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) { 36008c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4), 36018c2ecf20Sopenharmony_ci 0xffffffff); 36028c2ecf20Sopenharmony_ci } 36038c2ecf20Sopenharmony_ci sort_mode |= BNX2_RPM_SORT_USER0_MC_EN; 36048c2ecf20Sopenharmony_ci } 36058c2ecf20Sopenharmony_ci else { 36068c2ecf20Sopenharmony_ci /* Accept one or more multicast(s). */ 36078c2ecf20Sopenharmony_ci u32 mc_filter[NUM_MC_HASH_REGISTERS]; 36088c2ecf20Sopenharmony_ci u32 regidx; 36098c2ecf20Sopenharmony_ci u32 bit; 36108c2ecf20Sopenharmony_ci u32 crc; 36118c2ecf20Sopenharmony_ci 36128c2ecf20Sopenharmony_ci memset(mc_filter, 0, 4 * NUM_MC_HASH_REGISTERS); 36138c2ecf20Sopenharmony_ci 36148c2ecf20Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) { 36158c2ecf20Sopenharmony_ci crc = ether_crc_le(ETH_ALEN, ha->addr); 36168c2ecf20Sopenharmony_ci bit = crc & 0xff; 36178c2ecf20Sopenharmony_ci regidx = (bit & 0xe0) >> 5; 36188c2ecf20Sopenharmony_ci bit &= 0x1f; 36198c2ecf20Sopenharmony_ci mc_filter[regidx] |= (1 << bit); 36208c2ecf20Sopenharmony_ci } 36218c2ecf20Sopenharmony_ci 36228c2ecf20Sopenharmony_ci for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) { 36238c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4), 36248c2ecf20Sopenharmony_ci mc_filter[i]); 36258c2ecf20Sopenharmony_ci } 36268c2ecf20Sopenharmony_ci 36278c2ecf20Sopenharmony_ci sort_mode |= BNX2_RPM_SORT_USER0_MC_HSH_EN; 36288c2ecf20Sopenharmony_ci } 36298c2ecf20Sopenharmony_ci 36308c2ecf20Sopenharmony_ci if (netdev_uc_count(dev) > BNX2_MAX_UNICAST_ADDRESSES) { 36318c2ecf20Sopenharmony_ci rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS; 36328c2ecf20Sopenharmony_ci sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN | 36338c2ecf20Sopenharmony_ci BNX2_RPM_SORT_USER0_PROM_VLAN; 36348c2ecf20Sopenharmony_ci } else if (!(dev->flags & IFF_PROMISC)) { 36358c2ecf20Sopenharmony_ci /* Add all entries into to the match filter list */ 36368c2ecf20Sopenharmony_ci i = 0; 36378c2ecf20Sopenharmony_ci netdev_for_each_uc_addr(ha, dev) { 36388c2ecf20Sopenharmony_ci bnx2_set_mac_addr(bp, ha->addr, 36398c2ecf20Sopenharmony_ci i + BNX2_START_UNICAST_ADDRESS_INDEX); 36408c2ecf20Sopenharmony_ci sort_mode |= (1 << 36418c2ecf20Sopenharmony_ci (i + BNX2_START_UNICAST_ADDRESS_INDEX)); 36428c2ecf20Sopenharmony_ci i++; 36438c2ecf20Sopenharmony_ci } 36448c2ecf20Sopenharmony_ci 36458c2ecf20Sopenharmony_ci } 36468c2ecf20Sopenharmony_ci 36478c2ecf20Sopenharmony_ci if (rx_mode != bp->rx_mode) { 36488c2ecf20Sopenharmony_ci bp->rx_mode = rx_mode; 36498c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_EMAC_RX_MODE, rx_mode); 36508c2ecf20Sopenharmony_ci } 36518c2ecf20Sopenharmony_ci 36528c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_RPM_SORT_USER0, 0x0); 36538c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_RPM_SORT_USER0, sort_mode); 36548c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_RPM_SORT_USER0, sort_mode | BNX2_RPM_SORT_USER0_ENA); 36558c2ecf20Sopenharmony_ci 36568c2ecf20Sopenharmony_ci spin_unlock_bh(&bp->phy_lock); 36578c2ecf20Sopenharmony_ci} 36588c2ecf20Sopenharmony_ci 36598c2ecf20Sopenharmony_cistatic int 36608c2ecf20Sopenharmony_cicheck_fw_section(const struct firmware *fw, 36618c2ecf20Sopenharmony_ci const struct bnx2_fw_file_section *section, 36628c2ecf20Sopenharmony_ci u32 alignment, bool non_empty) 36638c2ecf20Sopenharmony_ci{ 36648c2ecf20Sopenharmony_ci u32 offset = be32_to_cpu(section->offset); 36658c2ecf20Sopenharmony_ci u32 len = be32_to_cpu(section->len); 36668c2ecf20Sopenharmony_ci 36678c2ecf20Sopenharmony_ci if ((offset == 0 && len != 0) || offset >= fw->size || offset & 3) 36688c2ecf20Sopenharmony_ci return -EINVAL; 36698c2ecf20Sopenharmony_ci if ((non_empty && len == 0) || len > fw->size - offset || 36708c2ecf20Sopenharmony_ci len & (alignment - 1)) 36718c2ecf20Sopenharmony_ci return -EINVAL; 36728c2ecf20Sopenharmony_ci return 0; 36738c2ecf20Sopenharmony_ci} 36748c2ecf20Sopenharmony_ci 36758c2ecf20Sopenharmony_cistatic int 36768c2ecf20Sopenharmony_cicheck_mips_fw_entry(const struct firmware *fw, 36778c2ecf20Sopenharmony_ci const struct bnx2_mips_fw_file_entry *entry) 36788c2ecf20Sopenharmony_ci{ 36798c2ecf20Sopenharmony_ci if (check_fw_section(fw, &entry->text, 4, true) || 36808c2ecf20Sopenharmony_ci check_fw_section(fw, &entry->data, 4, false) || 36818c2ecf20Sopenharmony_ci check_fw_section(fw, &entry->rodata, 4, false)) 36828c2ecf20Sopenharmony_ci return -EINVAL; 36838c2ecf20Sopenharmony_ci return 0; 36848c2ecf20Sopenharmony_ci} 36858c2ecf20Sopenharmony_ci 36868c2ecf20Sopenharmony_cistatic void bnx2_release_firmware(struct bnx2 *bp) 36878c2ecf20Sopenharmony_ci{ 36888c2ecf20Sopenharmony_ci if (bp->rv2p_firmware) { 36898c2ecf20Sopenharmony_ci release_firmware(bp->mips_firmware); 36908c2ecf20Sopenharmony_ci release_firmware(bp->rv2p_firmware); 36918c2ecf20Sopenharmony_ci bp->rv2p_firmware = NULL; 36928c2ecf20Sopenharmony_ci } 36938c2ecf20Sopenharmony_ci} 36948c2ecf20Sopenharmony_ci 36958c2ecf20Sopenharmony_cistatic int bnx2_request_uncached_firmware(struct bnx2 *bp) 36968c2ecf20Sopenharmony_ci{ 36978c2ecf20Sopenharmony_ci const char *mips_fw_file, *rv2p_fw_file; 36988c2ecf20Sopenharmony_ci const struct bnx2_mips_fw_file *mips_fw; 36998c2ecf20Sopenharmony_ci const struct bnx2_rv2p_fw_file *rv2p_fw; 37008c2ecf20Sopenharmony_ci int rc; 37018c2ecf20Sopenharmony_ci 37028c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5709) { 37038c2ecf20Sopenharmony_ci mips_fw_file = FW_MIPS_FILE_09; 37048c2ecf20Sopenharmony_ci if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5709_A0) || 37058c2ecf20Sopenharmony_ci (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5709_A1)) 37068c2ecf20Sopenharmony_ci rv2p_fw_file = FW_RV2P_FILE_09_Ax; 37078c2ecf20Sopenharmony_ci else 37088c2ecf20Sopenharmony_ci rv2p_fw_file = FW_RV2P_FILE_09; 37098c2ecf20Sopenharmony_ci } else { 37108c2ecf20Sopenharmony_ci mips_fw_file = FW_MIPS_FILE_06; 37118c2ecf20Sopenharmony_ci rv2p_fw_file = FW_RV2P_FILE_06; 37128c2ecf20Sopenharmony_ci } 37138c2ecf20Sopenharmony_ci 37148c2ecf20Sopenharmony_ci rc = request_firmware(&bp->mips_firmware, mips_fw_file, &bp->pdev->dev); 37158c2ecf20Sopenharmony_ci if (rc) { 37168c2ecf20Sopenharmony_ci pr_err("Can't load firmware file \"%s\"\n", mips_fw_file); 37178c2ecf20Sopenharmony_ci goto out; 37188c2ecf20Sopenharmony_ci } 37198c2ecf20Sopenharmony_ci 37208c2ecf20Sopenharmony_ci rc = request_firmware(&bp->rv2p_firmware, rv2p_fw_file, &bp->pdev->dev); 37218c2ecf20Sopenharmony_ci if (rc) { 37228c2ecf20Sopenharmony_ci pr_err("Can't load firmware file \"%s\"\n", rv2p_fw_file); 37238c2ecf20Sopenharmony_ci goto err_release_mips_firmware; 37248c2ecf20Sopenharmony_ci } 37258c2ecf20Sopenharmony_ci mips_fw = (const struct bnx2_mips_fw_file *) bp->mips_firmware->data; 37268c2ecf20Sopenharmony_ci rv2p_fw = (const struct bnx2_rv2p_fw_file *) bp->rv2p_firmware->data; 37278c2ecf20Sopenharmony_ci if (bp->mips_firmware->size < sizeof(*mips_fw) || 37288c2ecf20Sopenharmony_ci check_mips_fw_entry(bp->mips_firmware, &mips_fw->com) || 37298c2ecf20Sopenharmony_ci check_mips_fw_entry(bp->mips_firmware, &mips_fw->cp) || 37308c2ecf20Sopenharmony_ci check_mips_fw_entry(bp->mips_firmware, &mips_fw->rxp) || 37318c2ecf20Sopenharmony_ci check_mips_fw_entry(bp->mips_firmware, &mips_fw->tpat) || 37328c2ecf20Sopenharmony_ci check_mips_fw_entry(bp->mips_firmware, &mips_fw->txp)) { 37338c2ecf20Sopenharmony_ci pr_err("Firmware file \"%s\" is invalid\n", mips_fw_file); 37348c2ecf20Sopenharmony_ci rc = -EINVAL; 37358c2ecf20Sopenharmony_ci goto err_release_firmware; 37368c2ecf20Sopenharmony_ci } 37378c2ecf20Sopenharmony_ci if (bp->rv2p_firmware->size < sizeof(*rv2p_fw) || 37388c2ecf20Sopenharmony_ci check_fw_section(bp->rv2p_firmware, &rv2p_fw->proc1.rv2p, 8, true) || 37398c2ecf20Sopenharmony_ci check_fw_section(bp->rv2p_firmware, &rv2p_fw->proc2.rv2p, 8, true)) { 37408c2ecf20Sopenharmony_ci pr_err("Firmware file \"%s\" is invalid\n", rv2p_fw_file); 37418c2ecf20Sopenharmony_ci rc = -EINVAL; 37428c2ecf20Sopenharmony_ci goto err_release_firmware; 37438c2ecf20Sopenharmony_ci } 37448c2ecf20Sopenharmony_ciout: 37458c2ecf20Sopenharmony_ci return rc; 37468c2ecf20Sopenharmony_ci 37478c2ecf20Sopenharmony_cierr_release_firmware: 37488c2ecf20Sopenharmony_ci release_firmware(bp->rv2p_firmware); 37498c2ecf20Sopenharmony_ci bp->rv2p_firmware = NULL; 37508c2ecf20Sopenharmony_cierr_release_mips_firmware: 37518c2ecf20Sopenharmony_ci release_firmware(bp->mips_firmware); 37528c2ecf20Sopenharmony_ci goto out; 37538c2ecf20Sopenharmony_ci} 37548c2ecf20Sopenharmony_ci 37558c2ecf20Sopenharmony_cistatic int bnx2_request_firmware(struct bnx2 *bp) 37568c2ecf20Sopenharmony_ci{ 37578c2ecf20Sopenharmony_ci return bp->rv2p_firmware ? 0 : bnx2_request_uncached_firmware(bp); 37588c2ecf20Sopenharmony_ci} 37598c2ecf20Sopenharmony_ci 37608c2ecf20Sopenharmony_cistatic u32 37618c2ecf20Sopenharmony_cirv2p_fw_fixup(u32 rv2p_proc, int idx, u32 loc, u32 rv2p_code) 37628c2ecf20Sopenharmony_ci{ 37638c2ecf20Sopenharmony_ci switch (idx) { 37648c2ecf20Sopenharmony_ci case RV2P_P1_FIXUP_PAGE_SIZE_IDX: 37658c2ecf20Sopenharmony_ci rv2p_code &= ~RV2P_BD_PAGE_SIZE_MSK; 37668c2ecf20Sopenharmony_ci rv2p_code |= RV2P_BD_PAGE_SIZE; 37678c2ecf20Sopenharmony_ci break; 37688c2ecf20Sopenharmony_ci } 37698c2ecf20Sopenharmony_ci return rv2p_code; 37708c2ecf20Sopenharmony_ci} 37718c2ecf20Sopenharmony_ci 37728c2ecf20Sopenharmony_cistatic int 37738c2ecf20Sopenharmony_ciload_rv2p_fw(struct bnx2 *bp, u32 rv2p_proc, 37748c2ecf20Sopenharmony_ci const struct bnx2_rv2p_fw_file_entry *fw_entry) 37758c2ecf20Sopenharmony_ci{ 37768c2ecf20Sopenharmony_ci u32 rv2p_code_len, file_offset; 37778c2ecf20Sopenharmony_ci __be32 *rv2p_code; 37788c2ecf20Sopenharmony_ci int i; 37798c2ecf20Sopenharmony_ci u32 val, cmd, addr; 37808c2ecf20Sopenharmony_ci 37818c2ecf20Sopenharmony_ci rv2p_code_len = be32_to_cpu(fw_entry->rv2p.len); 37828c2ecf20Sopenharmony_ci file_offset = be32_to_cpu(fw_entry->rv2p.offset); 37838c2ecf20Sopenharmony_ci 37848c2ecf20Sopenharmony_ci rv2p_code = (__be32 *)(bp->rv2p_firmware->data + file_offset); 37858c2ecf20Sopenharmony_ci 37868c2ecf20Sopenharmony_ci if (rv2p_proc == RV2P_PROC1) { 37878c2ecf20Sopenharmony_ci cmd = BNX2_RV2P_PROC1_ADDR_CMD_RDWR; 37888c2ecf20Sopenharmony_ci addr = BNX2_RV2P_PROC1_ADDR_CMD; 37898c2ecf20Sopenharmony_ci } else { 37908c2ecf20Sopenharmony_ci cmd = BNX2_RV2P_PROC2_ADDR_CMD_RDWR; 37918c2ecf20Sopenharmony_ci addr = BNX2_RV2P_PROC2_ADDR_CMD; 37928c2ecf20Sopenharmony_ci } 37938c2ecf20Sopenharmony_ci 37948c2ecf20Sopenharmony_ci for (i = 0; i < rv2p_code_len; i += 8) { 37958c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_RV2P_INSTR_HIGH, be32_to_cpu(*rv2p_code)); 37968c2ecf20Sopenharmony_ci rv2p_code++; 37978c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_RV2P_INSTR_LOW, be32_to_cpu(*rv2p_code)); 37988c2ecf20Sopenharmony_ci rv2p_code++; 37998c2ecf20Sopenharmony_ci 38008c2ecf20Sopenharmony_ci val = (i / 8) | cmd; 38018c2ecf20Sopenharmony_ci BNX2_WR(bp, addr, val); 38028c2ecf20Sopenharmony_ci } 38038c2ecf20Sopenharmony_ci 38048c2ecf20Sopenharmony_ci rv2p_code = (__be32 *)(bp->rv2p_firmware->data + file_offset); 38058c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) { 38068c2ecf20Sopenharmony_ci u32 loc, code; 38078c2ecf20Sopenharmony_ci 38088c2ecf20Sopenharmony_ci loc = be32_to_cpu(fw_entry->fixup[i]); 38098c2ecf20Sopenharmony_ci if (loc && ((loc * 4) < rv2p_code_len)) { 38108c2ecf20Sopenharmony_ci code = be32_to_cpu(*(rv2p_code + loc - 1)); 38118c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_RV2P_INSTR_HIGH, code); 38128c2ecf20Sopenharmony_ci code = be32_to_cpu(*(rv2p_code + loc)); 38138c2ecf20Sopenharmony_ci code = rv2p_fw_fixup(rv2p_proc, i, loc, code); 38148c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_RV2P_INSTR_LOW, code); 38158c2ecf20Sopenharmony_ci 38168c2ecf20Sopenharmony_ci val = (loc / 2) | cmd; 38178c2ecf20Sopenharmony_ci BNX2_WR(bp, addr, val); 38188c2ecf20Sopenharmony_ci } 38198c2ecf20Sopenharmony_ci } 38208c2ecf20Sopenharmony_ci 38218c2ecf20Sopenharmony_ci /* Reset the processor, un-stall is done later. */ 38228c2ecf20Sopenharmony_ci if (rv2p_proc == RV2P_PROC1) { 38238c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC1_RESET); 38248c2ecf20Sopenharmony_ci } 38258c2ecf20Sopenharmony_ci else { 38268c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC2_RESET); 38278c2ecf20Sopenharmony_ci } 38288c2ecf20Sopenharmony_ci 38298c2ecf20Sopenharmony_ci return 0; 38308c2ecf20Sopenharmony_ci} 38318c2ecf20Sopenharmony_ci 38328c2ecf20Sopenharmony_cistatic int 38338c2ecf20Sopenharmony_ciload_cpu_fw(struct bnx2 *bp, const struct cpu_reg *cpu_reg, 38348c2ecf20Sopenharmony_ci const struct bnx2_mips_fw_file_entry *fw_entry) 38358c2ecf20Sopenharmony_ci{ 38368c2ecf20Sopenharmony_ci u32 addr, len, file_offset; 38378c2ecf20Sopenharmony_ci __be32 *data; 38388c2ecf20Sopenharmony_ci u32 offset; 38398c2ecf20Sopenharmony_ci u32 val; 38408c2ecf20Sopenharmony_ci 38418c2ecf20Sopenharmony_ci /* Halt the CPU. */ 38428c2ecf20Sopenharmony_ci val = bnx2_reg_rd_ind(bp, cpu_reg->mode); 38438c2ecf20Sopenharmony_ci val |= cpu_reg->mode_value_halt; 38448c2ecf20Sopenharmony_ci bnx2_reg_wr_ind(bp, cpu_reg->mode, val); 38458c2ecf20Sopenharmony_ci bnx2_reg_wr_ind(bp, cpu_reg->state, cpu_reg->state_value_clear); 38468c2ecf20Sopenharmony_ci 38478c2ecf20Sopenharmony_ci /* Load the Text area. */ 38488c2ecf20Sopenharmony_ci addr = be32_to_cpu(fw_entry->text.addr); 38498c2ecf20Sopenharmony_ci len = be32_to_cpu(fw_entry->text.len); 38508c2ecf20Sopenharmony_ci file_offset = be32_to_cpu(fw_entry->text.offset); 38518c2ecf20Sopenharmony_ci data = (__be32 *)(bp->mips_firmware->data + file_offset); 38528c2ecf20Sopenharmony_ci 38538c2ecf20Sopenharmony_ci offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base); 38548c2ecf20Sopenharmony_ci if (len) { 38558c2ecf20Sopenharmony_ci int j; 38568c2ecf20Sopenharmony_ci 38578c2ecf20Sopenharmony_ci for (j = 0; j < (len / 4); j++, offset += 4) 38588c2ecf20Sopenharmony_ci bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j])); 38598c2ecf20Sopenharmony_ci } 38608c2ecf20Sopenharmony_ci 38618c2ecf20Sopenharmony_ci /* Load the Data area. */ 38628c2ecf20Sopenharmony_ci addr = be32_to_cpu(fw_entry->data.addr); 38638c2ecf20Sopenharmony_ci len = be32_to_cpu(fw_entry->data.len); 38648c2ecf20Sopenharmony_ci file_offset = be32_to_cpu(fw_entry->data.offset); 38658c2ecf20Sopenharmony_ci data = (__be32 *)(bp->mips_firmware->data + file_offset); 38668c2ecf20Sopenharmony_ci 38678c2ecf20Sopenharmony_ci offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base); 38688c2ecf20Sopenharmony_ci if (len) { 38698c2ecf20Sopenharmony_ci int j; 38708c2ecf20Sopenharmony_ci 38718c2ecf20Sopenharmony_ci for (j = 0; j < (len / 4); j++, offset += 4) 38728c2ecf20Sopenharmony_ci bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j])); 38738c2ecf20Sopenharmony_ci } 38748c2ecf20Sopenharmony_ci 38758c2ecf20Sopenharmony_ci /* Load the Read-Only area. */ 38768c2ecf20Sopenharmony_ci addr = be32_to_cpu(fw_entry->rodata.addr); 38778c2ecf20Sopenharmony_ci len = be32_to_cpu(fw_entry->rodata.len); 38788c2ecf20Sopenharmony_ci file_offset = be32_to_cpu(fw_entry->rodata.offset); 38798c2ecf20Sopenharmony_ci data = (__be32 *)(bp->mips_firmware->data + file_offset); 38808c2ecf20Sopenharmony_ci 38818c2ecf20Sopenharmony_ci offset = cpu_reg->spad_base + (addr - cpu_reg->mips_view_base); 38828c2ecf20Sopenharmony_ci if (len) { 38838c2ecf20Sopenharmony_ci int j; 38848c2ecf20Sopenharmony_ci 38858c2ecf20Sopenharmony_ci for (j = 0; j < (len / 4); j++, offset += 4) 38868c2ecf20Sopenharmony_ci bnx2_reg_wr_ind(bp, offset, be32_to_cpu(data[j])); 38878c2ecf20Sopenharmony_ci } 38888c2ecf20Sopenharmony_ci 38898c2ecf20Sopenharmony_ci /* Clear the pre-fetch instruction. */ 38908c2ecf20Sopenharmony_ci bnx2_reg_wr_ind(bp, cpu_reg->inst, 0); 38918c2ecf20Sopenharmony_ci 38928c2ecf20Sopenharmony_ci val = be32_to_cpu(fw_entry->start_addr); 38938c2ecf20Sopenharmony_ci bnx2_reg_wr_ind(bp, cpu_reg->pc, val); 38948c2ecf20Sopenharmony_ci 38958c2ecf20Sopenharmony_ci /* Start the CPU. */ 38968c2ecf20Sopenharmony_ci val = bnx2_reg_rd_ind(bp, cpu_reg->mode); 38978c2ecf20Sopenharmony_ci val &= ~cpu_reg->mode_value_halt; 38988c2ecf20Sopenharmony_ci bnx2_reg_wr_ind(bp, cpu_reg->state, cpu_reg->state_value_clear); 38998c2ecf20Sopenharmony_ci bnx2_reg_wr_ind(bp, cpu_reg->mode, val); 39008c2ecf20Sopenharmony_ci 39018c2ecf20Sopenharmony_ci return 0; 39028c2ecf20Sopenharmony_ci} 39038c2ecf20Sopenharmony_ci 39048c2ecf20Sopenharmony_cistatic int 39058c2ecf20Sopenharmony_cibnx2_init_cpus(struct bnx2 *bp) 39068c2ecf20Sopenharmony_ci{ 39078c2ecf20Sopenharmony_ci const struct bnx2_mips_fw_file *mips_fw = 39088c2ecf20Sopenharmony_ci (const struct bnx2_mips_fw_file *) bp->mips_firmware->data; 39098c2ecf20Sopenharmony_ci const struct bnx2_rv2p_fw_file *rv2p_fw = 39108c2ecf20Sopenharmony_ci (const struct bnx2_rv2p_fw_file *) bp->rv2p_firmware->data; 39118c2ecf20Sopenharmony_ci int rc; 39128c2ecf20Sopenharmony_ci 39138c2ecf20Sopenharmony_ci /* Initialize the RV2P processor. */ 39148c2ecf20Sopenharmony_ci load_rv2p_fw(bp, RV2P_PROC1, &rv2p_fw->proc1); 39158c2ecf20Sopenharmony_ci load_rv2p_fw(bp, RV2P_PROC2, &rv2p_fw->proc2); 39168c2ecf20Sopenharmony_ci 39178c2ecf20Sopenharmony_ci /* Initialize the RX Processor. */ 39188c2ecf20Sopenharmony_ci rc = load_cpu_fw(bp, &cpu_reg_rxp, &mips_fw->rxp); 39198c2ecf20Sopenharmony_ci if (rc) 39208c2ecf20Sopenharmony_ci goto init_cpu_err; 39218c2ecf20Sopenharmony_ci 39228c2ecf20Sopenharmony_ci /* Initialize the TX Processor. */ 39238c2ecf20Sopenharmony_ci rc = load_cpu_fw(bp, &cpu_reg_txp, &mips_fw->txp); 39248c2ecf20Sopenharmony_ci if (rc) 39258c2ecf20Sopenharmony_ci goto init_cpu_err; 39268c2ecf20Sopenharmony_ci 39278c2ecf20Sopenharmony_ci /* Initialize the TX Patch-up Processor. */ 39288c2ecf20Sopenharmony_ci rc = load_cpu_fw(bp, &cpu_reg_tpat, &mips_fw->tpat); 39298c2ecf20Sopenharmony_ci if (rc) 39308c2ecf20Sopenharmony_ci goto init_cpu_err; 39318c2ecf20Sopenharmony_ci 39328c2ecf20Sopenharmony_ci /* Initialize the Completion Processor. */ 39338c2ecf20Sopenharmony_ci rc = load_cpu_fw(bp, &cpu_reg_com, &mips_fw->com); 39348c2ecf20Sopenharmony_ci if (rc) 39358c2ecf20Sopenharmony_ci goto init_cpu_err; 39368c2ecf20Sopenharmony_ci 39378c2ecf20Sopenharmony_ci /* Initialize the Command Processor. */ 39388c2ecf20Sopenharmony_ci rc = load_cpu_fw(bp, &cpu_reg_cp, &mips_fw->cp); 39398c2ecf20Sopenharmony_ci 39408c2ecf20Sopenharmony_ciinit_cpu_err: 39418c2ecf20Sopenharmony_ci return rc; 39428c2ecf20Sopenharmony_ci} 39438c2ecf20Sopenharmony_ci 39448c2ecf20Sopenharmony_cistatic void 39458c2ecf20Sopenharmony_cibnx2_setup_wol(struct bnx2 *bp) 39468c2ecf20Sopenharmony_ci{ 39478c2ecf20Sopenharmony_ci int i; 39488c2ecf20Sopenharmony_ci u32 val, wol_msg; 39498c2ecf20Sopenharmony_ci 39508c2ecf20Sopenharmony_ci if (bp->wol) { 39518c2ecf20Sopenharmony_ci u32 advertising; 39528c2ecf20Sopenharmony_ci u8 autoneg; 39538c2ecf20Sopenharmony_ci 39548c2ecf20Sopenharmony_ci autoneg = bp->autoneg; 39558c2ecf20Sopenharmony_ci advertising = bp->advertising; 39568c2ecf20Sopenharmony_ci 39578c2ecf20Sopenharmony_ci if (bp->phy_port == PORT_TP) { 39588c2ecf20Sopenharmony_ci bp->autoneg = AUTONEG_SPEED; 39598c2ecf20Sopenharmony_ci bp->advertising = ADVERTISED_10baseT_Half | 39608c2ecf20Sopenharmony_ci ADVERTISED_10baseT_Full | 39618c2ecf20Sopenharmony_ci ADVERTISED_100baseT_Half | 39628c2ecf20Sopenharmony_ci ADVERTISED_100baseT_Full | 39638c2ecf20Sopenharmony_ci ADVERTISED_Autoneg; 39648c2ecf20Sopenharmony_ci } 39658c2ecf20Sopenharmony_ci 39668c2ecf20Sopenharmony_ci spin_lock_bh(&bp->phy_lock); 39678c2ecf20Sopenharmony_ci bnx2_setup_phy(bp, bp->phy_port); 39688c2ecf20Sopenharmony_ci spin_unlock_bh(&bp->phy_lock); 39698c2ecf20Sopenharmony_ci 39708c2ecf20Sopenharmony_ci bp->autoneg = autoneg; 39718c2ecf20Sopenharmony_ci bp->advertising = advertising; 39728c2ecf20Sopenharmony_ci 39738c2ecf20Sopenharmony_ci bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0); 39748c2ecf20Sopenharmony_ci 39758c2ecf20Sopenharmony_ci val = BNX2_RD(bp, BNX2_EMAC_MODE); 39768c2ecf20Sopenharmony_ci 39778c2ecf20Sopenharmony_ci /* Enable port mode. */ 39788c2ecf20Sopenharmony_ci val &= ~BNX2_EMAC_MODE_PORT; 39798c2ecf20Sopenharmony_ci val |= BNX2_EMAC_MODE_MPKT_RCVD | 39808c2ecf20Sopenharmony_ci BNX2_EMAC_MODE_ACPI_RCVD | 39818c2ecf20Sopenharmony_ci BNX2_EMAC_MODE_MPKT; 39828c2ecf20Sopenharmony_ci if (bp->phy_port == PORT_TP) { 39838c2ecf20Sopenharmony_ci val |= BNX2_EMAC_MODE_PORT_MII; 39848c2ecf20Sopenharmony_ci } else { 39858c2ecf20Sopenharmony_ci val |= BNX2_EMAC_MODE_PORT_GMII; 39868c2ecf20Sopenharmony_ci if (bp->line_speed == SPEED_2500) 39878c2ecf20Sopenharmony_ci val |= BNX2_EMAC_MODE_25G_MODE; 39888c2ecf20Sopenharmony_ci } 39898c2ecf20Sopenharmony_ci 39908c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_EMAC_MODE, val); 39918c2ecf20Sopenharmony_ci 39928c2ecf20Sopenharmony_ci /* receive all multicast */ 39938c2ecf20Sopenharmony_ci for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) { 39948c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4), 39958c2ecf20Sopenharmony_ci 0xffffffff); 39968c2ecf20Sopenharmony_ci } 39978c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_EMAC_RX_MODE, BNX2_EMAC_RX_MODE_SORT_MODE); 39988c2ecf20Sopenharmony_ci 39998c2ecf20Sopenharmony_ci val = 1 | BNX2_RPM_SORT_USER0_BC_EN | BNX2_RPM_SORT_USER0_MC_EN; 40008c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_RPM_SORT_USER0, 0x0); 40018c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_RPM_SORT_USER0, val); 40028c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_RPM_SORT_USER0, val | BNX2_RPM_SORT_USER0_ENA); 40038c2ecf20Sopenharmony_ci 40048c2ecf20Sopenharmony_ci /* Need to enable EMAC and RPM for WOL. */ 40058c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_MISC_ENABLE_SET_BITS, 40068c2ecf20Sopenharmony_ci BNX2_MISC_ENABLE_SET_BITS_RX_PARSER_MAC_ENABLE | 40078c2ecf20Sopenharmony_ci BNX2_MISC_ENABLE_SET_BITS_TX_HEADER_Q_ENABLE | 40088c2ecf20Sopenharmony_ci BNX2_MISC_ENABLE_SET_BITS_EMAC_ENABLE); 40098c2ecf20Sopenharmony_ci 40108c2ecf20Sopenharmony_ci val = BNX2_RD(bp, BNX2_RPM_CONFIG); 40118c2ecf20Sopenharmony_ci val &= ~BNX2_RPM_CONFIG_ACPI_ENA; 40128c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_RPM_CONFIG, val); 40138c2ecf20Sopenharmony_ci 40148c2ecf20Sopenharmony_ci wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_WOL; 40158c2ecf20Sopenharmony_ci } else { 40168c2ecf20Sopenharmony_ci wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL; 40178c2ecf20Sopenharmony_ci } 40188c2ecf20Sopenharmony_ci 40198c2ecf20Sopenharmony_ci if (!(bp->flags & BNX2_FLAG_NO_WOL)) { 40208c2ecf20Sopenharmony_ci u32 val; 40218c2ecf20Sopenharmony_ci 40228c2ecf20Sopenharmony_ci wol_msg |= BNX2_DRV_MSG_DATA_WAIT3; 40238c2ecf20Sopenharmony_ci if (bp->fw_last_msg || BNX2_CHIP(bp) != BNX2_CHIP_5709) { 40248c2ecf20Sopenharmony_ci bnx2_fw_sync(bp, wol_msg, 1, 0); 40258c2ecf20Sopenharmony_ci return; 40268c2ecf20Sopenharmony_ci } 40278c2ecf20Sopenharmony_ci /* Tell firmware not to power down the PHY yet, otherwise 40288c2ecf20Sopenharmony_ci * the chip will take a long time to respond to MMIO reads. 40298c2ecf20Sopenharmony_ci */ 40308c2ecf20Sopenharmony_ci val = bnx2_shmem_rd(bp, BNX2_PORT_FEATURE); 40318c2ecf20Sopenharmony_ci bnx2_shmem_wr(bp, BNX2_PORT_FEATURE, 40328c2ecf20Sopenharmony_ci val | BNX2_PORT_FEATURE_ASF_ENABLED); 40338c2ecf20Sopenharmony_ci bnx2_fw_sync(bp, wol_msg, 1, 0); 40348c2ecf20Sopenharmony_ci bnx2_shmem_wr(bp, BNX2_PORT_FEATURE, val); 40358c2ecf20Sopenharmony_ci } 40368c2ecf20Sopenharmony_ci 40378c2ecf20Sopenharmony_ci} 40388c2ecf20Sopenharmony_ci 40398c2ecf20Sopenharmony_cistatic int 40408c2ecf20Sopenharmony_cibnx2_set_power_state(struct bnx2 *bp, pci_power_t state) 40418c2ecf20Sopenharmony_ci{ 40428c2ecf20Sopenharmony_ci switch (state) { 40438c2ecf20Sopenharmony_ci case PCI_D0: { 40448c2ecf20Sopenharmony_ci u32 val; 40458c2ecf20Sopenharmony_ci 40468c2ecf20Sopenharmony_ci pci_enable_wake(bp->pdev, PCI_D0, false); 40478c2ecf20Sopenharmony_ci pci_set_power_state(bp->pdev, PCI_D0); 40488c2ecf20Sopenharmony_ci 40498c2ecf20Sopenharmony_ci val = BNX2_RD(bp, BNX2_EMAC_MODE); 40508c2ecf20Sopenharmony_ci val |= BNX2_EMAC_MODE_MPKT_RCVD | BNX2_EMAC_MODE_ACPI_RCVD; 40518c2ecf20Sopenharmony_ci val &= ~BNX2_EMAC_MODE_MPKT; 40528c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_EMAC_MODE, val); 40538c2ecf20Sopenharmony_ci 40548c2ecf20Sopenharmony_ci val = BNX2_RD(bp, BNX2_RPM_CONFIG); 40558c2ecf20Sopenharmony_ci val &= ~BNX2_RPM_CONFIG_ACPI_ENA; 40568c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_RPM_CONFIG, val); 40578c2ecf20Sopenharmony_ci break; 40588c2ecf20Sopenharmony_ci } 40598c2ecf20Sopenharmony_ci case PCI_D3hot: { 40608c2ecf20Sopenharmony_ci bnx2_setup_wol(bp); 40618c2ecf20Sopenharmony_ci pci_wake_from_d3(bp->pdev, bp->wol); 40628c2ecf20Sopenharmony_ci if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) || 40638c2ecf20Sopenharmony_ci (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1)) { 40648c2ecf20Sopenharmony_ci 40658c2ecf20Sopenharmony_ci if (bp->wol) 40668c2ecf20Sopenharmony_ci pci_set_power_state(bp->pdev, PCI_D3hot); 40678c2ecf20Sopenharmony_ci break; 40688c2ecf20Sopenharmony_ci 40698c2ecf20Sopenharmony_ci } 40708c2ecf20Sopenharmony_ci if (!bp->fw_last_msg && BNX2_CHIP(bp) == BNX2_CHIP_5709) { 40718c2ecf20Sopenharmony_ci u32 val; 40728c2ecf20Sopenharmony_ci 40738c2ecf20Sopenharmony_ci /* Tell firmware not to power down the PHY yet, 40748c2ecf20Sopenharmony_ci * otherwise the other port may not respond to 40758c2ecf20Sopenharmony_ci * MMIO reads. 40768c2ecf20Sopenharmony_ci */ 40778c2ecf20Sopenharmony_ci val = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION); 40788c2ecf20Sopenharmony_ci val &= ~BNX2_CONDITION_PM_STATE_MASK; 40798c2ecf20Sopenharmony_ci val |= BNX2_CONDITION_PM_STATE_UNPREP; 40808c2ecf20Sopenharmony_ci bnx2_shmem_wr(bp, BNX2_BC_STATE_CONDITION, val); 40818c2ecf20Sopenharmony_ci } 40828c2ecf20Sopenharmony_ci pci_set_power_state(bp->pdev, PCI_D3hot); 40838c2ecf20Sopenharmony_ci 40848c2ecf20Sopenharmony_ci /* No more memory access after this point until 40858c2ecf20Sopenharmony_ci * device is brought back to D0. 40868c2ecf20Sopenharmony_ci */ 40878c2ecf20Sopenharmony_ci break; 40888c2ecf20Sopenharmony_ci } 40898c2ecf20Sopenharmony_ci default: 40908c2ecf20Sopenharmony_ci return -EINVAL; 40918c2ecf20Sopenharmony_ci } 40928c2ecf20Sopenharmony_ci return 0; 40938c2ecf20Sopenharmony_ci} 40948c2ecf20Sopenharmony_ci 40958c2ecf20Sopenharmony_cistatic int 40968c2ecf20Sopenharmony_cibnx2_acquire_nvram_lock(struct bnx2 *bp) 40978c2ecf20Sopenharmony_ci{ 40988c2ecf20Sopenharmony_ci u32 val; 40998c2ecf20Sopenharmony_ci int j; 41008c2ecf20Sopenharmony_ci 41018c2ecf20Sopenharmony_ci /* Request access to the flash interface. */ 41028c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_SET2); 41038c2ecf20Sopenharmony_ci for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) { 41048c2ecf20Sopenharmony_ci val = BNX2_RD(bp, BNX2_NVM_SW_ARB); 41058c2ecf20Sopenharmony_ci if (val & BNX2_NVM_SW_ARB_ARB_ARB2) 41068c2ecf20Sopenharmony_ci break; 41078c2ecf20Sopenharmony_ci 41088c2ecf20Sopenharmony_ci udelay(5); 41098c2ecf20Sopenharmony_ci } 41108c2ecf20Sopenharmony_ci 41118c2ecf20Sopenharmony_ci if (j >= NVRAM_TIMEOUT_COUNT) 41128c2ecf20Sopenharmony_ci return -EBUSY; 41138c2ecf20Sopenharmony_ci 41148c2ecf20Sopenharmony_ci return 0; 41158c2ecf20Sopenharmony_ci} 41168c2ecf20Sopenharmony_ci 41178c2ecf20Sopenharmony_cistatic int 41188c2ecf20Sopenharmony_cibnx2_release_nvram_lock(struct bnx2 *bp) 41198c2ecf20Sopenharmony_ci{ 41208c2ecf20Sopenharmony_ci int j; 41218c2ecf20Sopenharmony_ci u32 val; 41228c2ecf20Sopenharmony_ci 41238c2ecf20Sopenharmony_ci /* Relinquish nvram interface. */ 41248c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_CLR2); 41258c2ecf20Sopenharmony_ci 41268c2ecf20Sopenharmony_ci for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) { 41278c2ecf20Sopenharmony_ci val = BNX2_RD(bp, BNX2_NVM_SW_ARB); 41288c2ecf20Sopenharmony_ci if (!(val & BNX2_NVM_SW_ARB_ARB_ARB2)) 41298c2ecf20Sopenharmony_ci break; 41308c2ecf20Sopenharmony_ci 41318c2ecf20Sopenharmony_ci udelay(5); 41328c2ecf20Sopenharmony_ci } 41338c2ecf20Sopenharmony_ci 41348c2ecf20Sopenharmony_ci if (j >= NVRAM_TIMEOUT_COUNT) 41358c2ecf20Sopenharmony_ci return -EBUSY; 41368c2ecf20Sopenharmony_ci 41378c2ecf20Sopenharmony_ci return 0; 41388c2ecf20Sopenharmony_ci} 41398c2ecf20Sopenharmony_ci 41408c2ecf20Sopenharmony_ci 41418c2ecf20Sopenharmony_cistatic int 41428c2ecf20Sopenharmony_cibnx2_enable_nvram_write(struct bnx2 *bp) 41438c2ecf20Sopenharmony_ci{ 41448c2ecf20Sopenharmony_ci u32 val; 41458c2ecf20Sopenharmony_ci 41468c2ecf20Sopenharmony_ci val = BNX2_RD(bp, BNX2_MISC_CFG); 41478c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_MISC_CFG, val | BNX2_MISC_CFG_NVM_WR_EN_PCI); 41488c2ecf20Sopenharmony_ci 41498c2ecf20Sopenharmony_ci if (bp->flash_info->flags & BNX2_NV_WREN) { 41508c2ecf20Sopenharmony_ci int j; 41518c2ecf20Sopenharmony_ci 41528c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE); 41538c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_NVM_COMMAND, 41548c2ecf20Sopenharmony_ci BNX2_NVM_COMMAND_WREN | BNX2_NVM_COMMAND_DOIT); 41558c2ecf20Sopenharmony_ci 41568c2ecf20Sopenharmony_ci for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) { 41578c2ecf20Sopenharmony_ci udelay(5); 41588c2ecf20Sopenharmony_ci 41598c2ecf20Sopenharmony_ci val = BNX2_RD(bp, BNX2_NVM_COMMAND); 41608c2ecf20Sopenharmony_ci if (val & BNX2_NVM_COMMAND_DONE) 41618c2ecf20Sopenharmony_ci break; 41628c2ecf20Sopenharmony_ci } 41638c2ecf20Sopenharmony_ci 41648c2ecf20Sopenharmony_ci if (j >= NVRAM_TIMEOUT_COUNT) 41658c2ecf20Sopenharmony_ci return -EBUSY; 41668c2ecf20Sopenharmony_ci } 41678c2ecf20Sopenharmony_ci return 0; 41688c2ecf20Sopenharmony_ci} 41698c2ecf20Sopenharmony_ci 41708c2ecf20Sopenharmony_cistatic void 41718c2ecf20Sopenharmony_cibnx2_disable_nvram_write(struct bnx2 *bp) 41728c2ecf20Sopenharmony_ci{ 41738c2ecf20Sopenharmony_ci u32 val; 41748c2ecf20Sopenharmony_ci 41758c2ecf20Sopenharmony_ci val = BNX2_RD(bp, BNX2_MISC_CFG); 41768c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_MISC_CFG, val & ~BNX2_MISC_CFG_NVM_WR_EN); 41778c2ecf20Sopenharmony_ci} 41788c2ecf20Sopenharmony_ci 41798c2ecf20Sopenharmony_ci 41808c2ecf20Sopenharmony_cistatic void 41818c2ecf20Sopenharmony_cibnx2_enable_nvram_access(struct bnx2 *bp) 41828c2ecf20Sopenharmony_ci{ 41838c2ecf20Sopenharmony_ci u32 val; 41848c2ecf20Sopenharmony_ci 41858c2ecf20Sopenharmony_ci val = BNX2_RD(bp, BNX2_NVM_ACCESS_ENABLE); 41868c2ecf20Sopenharmony_ci /* Enable both bits, even on read. */ 41878c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_NVM_ACCESS_ENABLE, 41888c2ecf20Sopenharmony_ci val | BNX2_NVM_ACCESS_ENABLE_EN | BNX2_NVM_ACCESS_ENABLE_WR_EN); 41898c2ecf20Sopenharmony_ci} 41908c2ecf20Sopenharmony_ci 41918c2ecf20Sopenharmony_cistatic void 41928c2ecf20Sopenharmony_cibnx2_disable_nvram_access(struct bnx2 *bp) 41938c2ecf20Sopenharmony_ci{ 41948c2ecf20Sopenharmony_ci u32 val; 41958c2ecf20Sopenharmony_ci 41968c2ecf20Sopenharmony_ci val = BNX2_RD(bp, BNX2_NVM_ACCESS_ENABLE); 41978c2ecf20Sopenharmony_ci /* Disable both bits, even after read. */ 41988c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_NVM_ACCESS_ENABLE, 41998c2ecf20Sopenharmony_ci val & ~(BNX2_NVM_ACCESS_ENABLE_EN | 42008c2ecf20Sopenharmony_ci BNX2_NVM_ACCESS_ENABLE_WR_EN)); 42018c2ecf20Sopenharmony_ci} 42028c2ecf20Sopenharmony_ci 42038c2ecf20Sopenharmony_cistatic int 42048c2ecf20Sopenharmony_cibnx2_nvram_erase_page(struct bnx2 *bp, u32 offset) 42058c2ecf20Sopenharmony_ci{ 42068c2ecf20Sopenharmony_ci u32 cmd; 42078c2ecf20Sopenharmony_ci int j; 42088c2ecf20Sopenharmony_ci 42098c2ecf20Sopenharmony_ci if (bp->flash_info->flags & BNX2_NV_BUFFERED) 42108c2ecf20Sopenharmony_ci /* Buffered flash, no erase needed */ 42118c2ecf20Sopenharmony_ci return 0; 42128c2ecf20Sopenharmony_ci 42138c2ecf20Sopenharmony_ci /* Build an erase command */ 42148c2ecf20Sopenharmony_ci cmd = BNX2_NVM_COMMAND_ERASE | BNX2_NVM_COMMAND_WR | 42158c2ecf20Sopenharmony_ci BNX2_NVM_COMMAND_DOIT; 42168c2ecf20Sopenharmony_ci 42178c2ecf20Sopenharmony_ci /* Need to clear DONE bit separately. */ 42188c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE); 42198c2ecf20Sopenharmony_ci 42208c2ecf20Sopenharmony_ci /* Address of the NVRAM to read from. */ 42218c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE); 42228c2ecf20Sopenharmony_ci 42238c2ecf20Sopenharmony_ci /* Issue an erase command. */ 42248c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_NVM_COMMAND, cmd); 42258c2ecf20Sopenharmony_ci 42268c2ecf20Sopenharmony_ci /* Wait for completion. */ 42278c2ecf20Sopenharmony_ci for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) { 42288c2ecf20Sopenharmony_ci u32 val; 42298c2ecf20Sopenharmony_ci 42308c2ecf20Sopenharmony_ci udelay(5); 42318c2ecf20Sopenharmony_ci 42328c2ecf20Sopenharmony_ci val = BNX2_RD(bp, BNX2_NVM_COMMAND); 42338c2ecf20Sopenharmony_ci if (val & BNX2_NVM_COMMAND_DONE) 42348c2ecf20Sopenharmony_ci break; 42358c2ecf20Sopenharmony_ci } 42368c2ecf20Sopenharmony_ci 42378c2ecf20Sopenharmony_ci if (j >= NVRAM_TIMEOUT_COUNT) 42388c2ecf20Sopenharmony_ci return -EBUSY; 42398c2ecf20Sopenharmony_ci 42408c2ecf20Sopenharmony_ci return 0; 42418c2ecf20Sopenharmony_ci} 42428c2ecf20Sopenharmony_ci 42438c2ecf20Sopenharmony_cistatic int 42448c2ecf20Sopenharmony_cibnx2_nvram_read_dword(struct bnx2 *bp, u32 offset, u8 *ret_val, u32 cmd_flags) 42458c2ecf20Sopenharmony_ci{ 42468c2ecf20Sopenharmony_ci u32 cmd; 42478c2ecf20Sopenharmony_ci int j; 42488c2ecf20Sopenharmony_ci 42498c2ecf20Sopenharmony_ci /* Build the command word. */ 42508c2ecf20Sopenharmony_ci cmd = BNX2_NVM_COMMAND_DOIT | cmd_flags; 42518c2ecf20Sopenharmony_ci 42528c2ecf20Sopenharmony_ci /* Calculate an offset of a buffered flash, not needed for 5709. */ 42538c2ecf20Sopenharmony_ci if (bp->flash_info->flags & BNX2_NV_TRANSLATE) { 42548c2ecf20Sopenharmony_ci offset = ((offset / bp->flash_info->page_size) << 42558c2ecf20Sopenharmony_ci bp->flash_info->page_bits) + 42568c2ecf20Sopenharmony_ci (offset % bp->flash_info->page_size); 42578c2ecf20Sopenharmony_ci } 42588c2ecf20Sopenharmony_ci 42598c2ecf20Sopenharmony_ci /* Need to clear DONE bit separately. */ 42608c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE); 42618c2ecf20Sopenharmony_ci 42628c2ecf20Sopenharmony_ci /* Address of the NVRAM to read from. */ 42638c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE); 42648c2ecf20Sopenharmony_ci 42658c2ecf20Sopenharmony_ci /* Issue a read command. */ 42668c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_NVM_COMMAND, cmd); 42678c2ecf20Sopenharmony_ci 42688c2ecf20Sopenharmony_ci /* Wait for completion. */ 42698c2ecf20Sopenharmony_ci for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) { 42708c2ecf20Sopenharmony_ci u32 val; 42718c2ecf20Sopenharmony_ci 42728c2ecf20Sopenharmony_ci udelay(5); 42738c2ecf20Sopenharmony_ci 42748c2ecf20Sopenharmony_ci val = BNX2_RD(bp, BNX2_NVM_COMMAND); 42758c2ecf20Sopenharmony_ci if (val & BNX2_NVM_COMMAND_DONE) { 42768c2ecf20Sopenharmony_ci __be32 v = cpu_to_be32(BNX2_RD(bp, BNX2_NVM_READ)); 42778c2ecf20Sopenharmony_ci memcpy(ret_val, &v, 4); 42788c2ecf20Sopenharmony_ci break; 42798c2ecf20Sopenharmony_ci } 42808c2ecf20Sopenharmony_ci } 42818c2ecf20Sopenharmony_ci if (j >= NVRAM_TIMEOUT_COUNT) 42828c2ecf20Sopenharmony_ci return -EBUSY; 42838c2ecf20Sopenharmony_ci 42848c2ecf20Sopenharmony_ci return 0; 42858c2ecf20Sopenharmony_ci} 42868c2ecf20Sopenharmony_ci 42878c2ecf20Sopenharmony_ci 42888c2ecf20Sopenharmony_cistatic int 42898c2ecf20Sopenharmony_cibnx2_nvram_write_dword(struct bnx2 *bp, u32 offset, u8 *val, u32 cmd_flags) 42908c2ecf20Sopenharmony_ci{ 42918c2ecf20Sopenharmony_ci u32 cmd; 42928c2ecf20Sopenharmony_ci __be32 val32; 42938c2ecf20Sopenharmony_ci int j; 42948c2ecf20Sopenharmony_ci 42958c2ecf20Sopenharmony_ci /* Build the command word. */ 42968c2ecf20Sopenharmony_ci cmd = BNX2_NVM_COMMAND_DOIT | BNX2_NVM_COMMAND_WR | cmd_flags; 42978c2ecf20Sopenharmony_ci 42988c2ecf20Sopenharmony_ci /* Calculate an offset of a buffered flash, not needed for 5709. */ 42998c2ecf20Sopenharmony_ci if (bp->flash_info->flags & BNX2_NV_TRANSLATE) { 43008c2ecf20Sopenharmony_ci offset = ((offset / bp->flash_info->page_size) << 43018c2ecf20Sopenharmony_ci bp->flash_info->page_bits) + 43028c2ecf20Sopenharmony_ci (offset % bp->flash_info->page_size); 43038c2ecf20Sopenharmony_ci } 43048c2ecf20Sopenharmony_ci 43058c2ecf20Sopenharmony_ci /* Need to clear DONE bit separately. */ 43068c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE); 43078c2ecf20Sopenharmony_ci 43088c2ecf20Sopenharmony_ci memcpy(&val32, val, 4); 43098c2ecf20Sopenharmony_ci 43108c2ecf20Sopenharmony_ci /* Write the data. */ 43118c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_NVM_WRITE, be32_to_cpu(val32)); 43128c2ecf20Sopenharmony_ci 43138c2ecf20Sopenharmony_ci /* Address of the NVRAM to write to. */ 43148c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE); 43158c2ecf20Sopenharmony_ci 43168c2ecf20Sopenharmony_ci /* Issue the write command. */ 43178c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_NVM_COMMAND, cmd); 43188c2ecf20Sopenharmony_ci 43198c2ecf20Sopenharmony_ci /* Wait for completion. */ 43208c2ecf20Sopenharmony_ci for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) { 43218c2ecf20Sopenharmony_ci udelay(5); 43228c2ecf20Sopenharmony_ci 43238c2ecf20Sopenharmony_ci if (BNX2_RD(bp, BNX2_NVM_COMMAND) & BNX2_NVM_COMMAND_DONE) 43248c2ecf20Sopenharmony_ci break; 43258c2ecf20Sopenharmony_ci } 43268c2ecf20Sopenharmony_ci if (j >= NVRAM_TIMEOUT_COUNT) 43278c2ecf20Sopenharmony_ci return -EBUSY; 43288c2ecf20Sopenharmony_ci 43298c2ecf20Sopenharmony_ci return 0; 43308c2ecf20Sopenharmony_ci} 43318c2ecf20Sopenharmony_ci 43328c2ecf20Sopenharmony_cistatic int 43338c2ecf20Sopenharmony_cibnx2_init_nvram(struct bnx2 *bp) 43348c2ecf20Sopenharmony_ci{ 43358c2ecf20Sopenharmony_ci u32 val; 43368c2ecf20Sopenharmony_ci int j, entry_count, rc = 0; 43378c2ecf20Sopenharmony_ci const struct flash_spec *flash; 43388c2ecf20Sopenharmony_ci 43398c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5709) { 43408c2ecf20Sopenharmony_ci bp->flash_info = &flash_5709; 43418c2ecf20Sopenharmony_ci goto get_flash_size; 43428c2ecf20Sopenharmony_ci } 43438c2ecf20Sopenharmony_ci 43448c2ecf20Sopenharmony_ci /* Determine the selected interface. */ 43458c2ecf20Sopenharmony_ci val = BNX2_RD(bp, BNX2_NVM_CFG1); 43468c2ecf20Sopenharmony_ci 43478c2ecf20Sopenharmony_ci entry_count = ARRAY_SIZE(flash_table); 43488c2ecf20Sopenharmony_ci 43498c2ecf20Sopenharmony_ci if (val & 0x40000000) { 43508c2ecf20Sopenharmony_ci 43518c2ecf20Sopenharmony_ci /* Flash interface has been reconfigured */ 43528c2ecf20Sopenharmony_ci for (j = 0, flash = &flash_table[0]; j < entry_count; 43538c2ecf20Sopenharmony_ci j++, flash++) { 43548c2ecf20Sopenharmony_ci if ((val & FLASH_BACKUP_STRAP_MASK) == 43558c2ecf20Sopenharmony_ci (flash->config1 & FLASH_BACKUP_STRAP_MASK)) { 43568c2ecf20Sopenharmony_ci bp->flash_info = flash; 43578c2ecf20Sopenharmony_ci break; 43588c2ecf20Sopenharmony_ci } 43598c2ecf20Sopenharmony_ci } 43608c2ecf20Sopenharmony_ci } 43618c2ecf20Sopenharmony_ci else { 43628c2ecf20Sopenharmony_ci u32 mask; 43638c2ecf20Sopenharmony_ci /* Not yet been reconfigured */ 43648c2ecf20Sopenharmony_ci 43658c2ecf20Sopenharmony_ci if (val & (1 << 23)) 43668c2ecf20Sopenharmony_ci mask = FLASH_BACKUP_STRAP_MASK; 43678c2ecf20Sopenharmony_ci else 43688c2ecf20Sopenharmony_ci mask = FLASH_STRAP_MASK; 43698c2ecf20Sopenharmony_ci 43708c2ecf20Sopenharmony_ci for (j = 0, flash = &flash_table[0]; j < entry_count; 43718c2ecf20Sopenharmony_ci j++, flash++) { 43728c2ecf20Sopenharmony_ci 43738c2ecf20Sopenharmony_ci if ((val & mask) == (flash->strapping & mask)) { 43748c2ecf20Sopenharmony_ci bp->flash_info = flash; 43758c2ecf20Sopenharmony_ci 43768c2ecf20Sopenharmony_ci /* Request access to the flash interface. */ 43778c2ecf20Sopenharmony_ci if ((rc = bnx2_acquire_nvram_lock(bp)) != 0) 43788c2ecf20Sopenharmony_ci return rc; 43798c2ecf20Sopenharmony_ci 43808c2ecf20Sopenharmony_ci /* Enable access to flash interface */ 43818c2ecf20Sopenharmony_ci bnx2_enable_nvram_access(bp); 43828c2ecf20Sopenharmony_ci 43838c2ecf20Sopenharmony_ci /* Reconfigure the flash interface */ 43848c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_NVM_CFG1, flash->config1); 43858c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_NVM_CFG2, flash->config2); 43868c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_NVM_CFG3, flash->config3); 43878c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_NVM_WRITE1, flash->write1); 43888c2ecf20Sopenharmony_ci 43898c2ecf20Sopenharmony_ci /* Disable access to flash interface */ 43908c2ecf20Sopenharmony_ci bnx2_disable_nvram_access(bp); 43918c2ecf20Sopenharmony_ci bnx2_release_nvram_lock(bp); 43928c2ecf20Sopenharmony_ci 43938c2ecf20Sopenharmony_ci break; 43948c2ecf20Sopenharmony_ci } 43958c2ecf20Sopenharmony_ci } 43968c2ecf20Sopenharmony_ci } /* if (val & 0x40000000) */ 43978c2ecf20Sopenharmony_ci 43988c2ecf20Sopenharmony_ci if (j == entry_count) { 43998c2ecf20Sopenharmony_ci bp->flash_info = NULL; 44008c2ecf20Sopenharmony_ci pr_alert("Unknown flash/EEPROM type\n"); 44018c2ecf20Sopenharmony_ci return -ENODEV; 44028c2ecf20Sopenharmony_ci } 44038c2ecf20Sopenharmony_ci 44048c2ecf20Sopenharmony_ciget_flash_size: 44058c2ecf20Sopenharmony_ci val = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG2); 44068c2ecf20Sopenharmony_ci val &= BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK; 44078c2ecf20Sopenharmony_ci if (val) 44088c2ecf20Sopenharmony_ci bp->flash_size = val; 44098c2ecf20Sopenharmony_ci else 44108c2ecf20Sopenharmony_ci bp->flash_size = bp->flash_info->total_size; 44118c2ecf20Sopenharmony_ci 44128c2ecf20Sopenharmony_ci return rc; 44138c2ecf20Sopenharmony_ci} 44148c2ecf20Sopenharmony_ci 44158c2ecf20Sopenharmony_cistatic int 44168c2ecf20Sopenharmony_cibnx2_nvram_read(struct bnx2 *bp, u32 offset, u8 *ret_buf, 44178c2ecf20Sopenharmony_ci int buf_size) 44188c2ecf20Sopenharmony_ci{ 44198c2ecf20Sopenharmony_ci int rc = 0; 44208c2ecf20Sopenharmony_ci u32 cmd_flags, offset32, len32, extra; 44218c2ecf20Sopenharmony_ci 44228c2ecf20Sopenharmony_ci if (buf_size == 0) 44238c2ecf20Sopenharmony_ci return 0; 44248c2ecf20Sopenharmony_ci 44258c2ecf20Sopenharmony_ci /* Request access to the flash interface. */ 44268c2ecf20Sopenharmony_ci if ((rc = bnx2_acquire_nvram_lock(bp)) != 0) 44278c2ecf20Sopenharmony_ci return rc; 44288c2ecf20Sopenharmony_ci 44298c2ecf20Sopenharmony_ci /* Enable access to flash interface */ 44308c2ecf20Sopenharmony_ci bnx2_enable_nvram_access(bp); 44318c2ecf20Sopenharmony_ci 44328c2ecf20Sopenharmony_ci len32 = buf_size; 44338c2ecf20Sopenharmony_ci offset32 = offset; 44348c2ecf20Sopenharmony_ci extra = 0; 44358c2ecf20Sopenharmony_ci 44368c2ecf20Sopenharmony_ci cmd_flags = 0; 44378c2ecf20Sopenharmony_ci 44388c2ecf20Sopenharmony_ci if (offset32 & 3) { 44398c2ecf20Sopenharmony_ci u8 buf[4]; 44408c2ecf20Sopenharmony_ci u32 pre_len; 44418c2ecf20Sopenharmony_ci 44428c2ecf20Sopenharmony_ci offset32 &= ~3; 44438c2ecf20Sopenharmony_ci pre_len = 4 - (offset & 3); 44448c2ecf20Sopenharmony_ci 44458c2ecf20Sopenharmony_ci if (pre_len >= len32) { 44468c2ecf20Sopenharmony_ci pre_len = len32; 44478c2ecf20Sopenharmony_ci cmd_flags = BNX2_NVM_COMMAND_FIRST | 44488c2ecf20Sopenharmony_ci BNX2_NVM_COMMAND_LAST; 44498c2ecf20Sopenharmony_ci } 44508c2ecf20Sopenharmony_ci else { 44518c2ecf20Sopenharmony_ci cmd_flags = BNX2_NVM_COMMAND_FIRST; 44528c2ecf20Sopenharmony_ci } 44538c2ecf20Sopenharmony_ci 44548c2ecf20Sopenharmony_ci rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags); 44558c2ecf20Sopenharmony_ci 44568c2ecf20Sopenharmony_ci if (rc) 44578c2ecf20Sopenharmony_ci return rc; 44588c2ecf20Sopenharmony_ci 44598c2ecf20Sopenharmony_ci memcpy(ret_buf, buf + (offset & 3), pre_len); 44608c2ecf20Sopenharmony_ci 44618c2ecf20Sopenharmony_ci offset32 += 4; 44628c2ecf20Sopenharmony_ci ret_buf += pre_len; 44638c2ecf20Sopenharmony_ci len32 -= pre_len; 44648c2ecf20Sopenharmony_ci } 44658c2ecf20Sopenharmony_ci if (len32 & 3) { 44668c2ecf20Sopenharmony_ci extra = 4 - (len32 & 3); 44678c2ecf20Sopenharmony_ci len32 = (len32 + 4) & ~3; 44688c2ecf20Sopenharmony_ci } 44698c2ecf20Sopenharmony_ci 44708c2ecf20Sopenharmony_ci if (len32 == 4) { 44718c2ecf20Sopenharmony_ci u8 buf[4]; 44728c2ecf20Sopenharmony_ci 44738c2ecf20Sopenharmony_ci if (cmd_flags) 44748c2ecf20Sopenharmony_ci cmd_flags = BNX2_NVM_COMMAND_LAST; 44758c2ecf20Sopenharmony_ci else 44768c2ecf20Sopenharmony_ci cmd_flags = BNX2_NVM_COMMAND_FIRST | 44778c2ecf20Sopenharmony_ci BNX2_NVM_COMMAND_LAST; 44788c2ecf20Sopenharmony_ci 44798c2ecf20Sopenharmony_ci rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags); 44808c2ecf20Sopenharmony_ci 44818c2ecf20Sopenharmony_ci memcpy(ret_buf, buf, 4 - extra); 44828c2ecf20Sopenharmony_ci } 44838c2ecf20Sopenharmony_ci else if (len32 > 0) { 44848c2ecf20Sopenharmony_ci u8 buf[4]; 44858c2ecf20Sopenharmony_ci 44868c2ecf20Sopenharmony_ci /* Read the first word. */ 44878c2ecf20Sopenharmony_ci if (cmd_flags) 44888c2ecf20Sopenharmony_ci cmd_flags = 0; 44898c2ecf20Sopenharmony_ci else 44908c2ecf20Sopenharmony_ci cmd_flags = BNX2_NVM_COMMAND_FIRST; 44918c2ecf20Sopenharmony_ci 44928c2ecf20Sopenharmony_ci rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, cmd_flags); 44938c2ecf20Sopenharmony_ci 44948c2ecf20Sopenharmony_ci /* Advance to the next dword. */ 44958c2ecf20Sopenharmony_ci offset32 += 4; 44968c2ecf20Sopenharmony_ci ret_buf += 4; 44978c2ecf20Sopenharmony_ci len32 -= 4; 44988c2ecf20Sopenharmony_ci 44998c2ecf20Sopenharmony_ci while (len32 > 4 && rc == 0) { 45008c2ecf20Sopenharmony_ci rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, 0); 45018c2ecf20Sopenharmony_ci 45028c2ecf20Sopenharmony_ci /* Advance to the next dword. */ 45038c2ecf20Sopenharmony_ci offset32 += 4; 45048c2ecf20Sopenharmony_ci ret_buf += 4; 45058c2ecf20Sopenharmony_ci len32 -= 4; 45068c2ecf20Sopenharmony_ci } 45078c2ecf20Sopenharmony_ci 45088c2ecf20Sopenharmony_ci if (rc) 45098c2ecf20Sopenharmony_ci return rc; 45108c2ecf20Sopenharmony_ci 45118c2ecf20Sopenharmony_ci cmd_flags = BNX2_NVM_COMMAND_LAST; 45128c2ecf20Sopenharmony_ci rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags); 45138c2ecf20Sopenharmony_ci 45148c2ecf20Sopenharmony_ci memcpy(ret_buf, buf, 4 - extra); 45158c2ecf20Sopenharmony_ci } 45168c2ecf20Sopenharmony_ci 45178c2ecf20Sopenharmony_ci /* Disable access to flash interface */ 45188c2ecf20Sopenharmony_ci bnx2_disable_nvram_access(bp); 45198c2ecf20Sopenharmony_ci 45208c2ecf20Sopenharmony_ci bnx2_release_nvram_lock(bp); 45218c2ecf20Sopenharmony_ci 45228c2ecf20Sopenharmony_ci return rc; 45238c2ecf20Sopenharmony_ci} 45248c2ecf20Sopenharmony_ci 45258c2ecf20Sopenharmony_cistatic int 45268c2ecf20Sopenharmony_cibnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf, 45278c2ecf20Sopenharmony_ci int buf_size) 45288c2ecf20Sopenharmony_ci{ 45298c2ecf20Sopenharmony_ci u32 written, offset32, len32; 45308c2ecf20Sopenharmony_ci u8 *buf, start[4], end[4], *align_buf = NULL, *flash_buffer = NULL; 45318c2ecf20Sopenharmony_ci int rc = 0; 45328c2ecf20Sopenharmony_ci int align_start, align_end; 45338c2ecf20Sopenharmony_ci 45348c2ecf20Sopenharmony_ci buf = data_buf; 45358c2ecf20Sopenharmony_ci offset32 = offset; 45368c2ecf20Sopenharmony_ci len32 = buf_size; 45378c2ecf20Sopenharmony_ci align_start = align_end = 0; 45388c2ecf20Sopenharmony_ci 45398c2ecf20Sopenharmony_ci if ((align_start = (offset32 & 3))) { 45408c2ecf20Sopenharmony_ci offset32 &= ~3; 45418c2ecf20Sopenharmony_ci len32 += align_start; 45428c2ecf20Sopenharmony_ci if (len32 < 4) 45438c2ecf20Sopenharmony_ci len32 = 4; 45448c2ecf20Sopenharmony_ci if ((rc = bnx2_nvram_read(bp, offset32, start, 4))) 45458c2ecf20Sopenharmony_ci return rc; 45468c2ecf20Sopenharmony_ci } 45478c2ecf20Sopenharmony_ci 45488c2ecf20Sopenharmony_ci if (len32 & 3) { 45498c2ecf20Sopenharmony_ci align_end = 4 - (len32 & 3); 45508c2ecf20Sopenharmony_ci len32 += align_end; 45518c2ecf20Sopenharmony_ci if ((rc = bnx2_nvram_read(bp, offset32 + len32 - 4, end, 4))) 45528c2ecf20Sopenharmony_ci return rc; 45538c2ecf20Sopenharmony_ci } 45548c2ecf20Sopenharmony_ci 45558c2ecf20Sopenharmony_ci if (align_start || align_end) { 45568c2ecf20Sopenharmony_ci align_buf = kmalloc(len32, GFP_KERNEL); 45578c2ecf20Sopenharmony_ci if (!align_buf) 45588c2ecf20Sopenharmony_ci return -ENOMEM; 45598c2ecf20Sopenharmony_ci if (align_start) { 45608c2ecf20Sopenharmony_ci memcpy(align_buf, start, 4); 45618c2ecf20Sopenharmony_ci } 45628c2ecf20Sopenharmony_ci if (align_end) { 45638c2ecf20Sopenharmony_ci memcpy(align_buf + len32 - 4, end, 4); 45648c2ecf20Sopenharmony_ci } 45658c2ecf20Sopenharmony_ci memcpy(align_buf + align_start, data_buf, buf_size); 45668c2ecf20Sopenharmony_ci buf = align_buf; 45678c2ecf20Sopenharmony_ci } 45688c2ecf20Sopenharmony_ci 45698c2ecf20Sopenharmony_ci if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) { 45708c2ecf20Sopenharmony_ci flash_buffer = kmalloc(264, GFP_KERNEL); 45718c2ecf20Sopenharmony_ci if (!flash_buffer) { 45728c2ecf20Sopenharmony_ci rc = -ENOMEM; 45738c2ecf20Sopenharmony_ci goto nvram_write_end; 45748c2ecf20Sopenharmony_ci } 45758c2ecf20Sopenharmony_ci } 45768c2ecf20Sopenharmony_ci 45778c2ecf20Sopenharmony_ci written = 0; 45788c2ecf20Sopenharmony_ci while ((written < len32) && (rc == 0)) { 45798c2ecf20Sopenharmony_ci u32 page_start, page_end, data_start, data_end; 45808c2ecf20Sopenharmony_ci u32 addr, cmd_flags; 45818c2ecf20Sopenharmony_ci int i; 45828c2ecf20Sopenharmony_ci 45838c2ecf20Sopenharmony_ci /* Find the page_start addr */ 45848c2ecf20Sopenharmony_ci page_start = offset32 + written; 45858c2ecf20Sopenharmony_ci page_start -= (page_start % bp->flash_info->page_size); 45868c2ecf20Sopenharmony_ci /* Find the page_end addr */ 45878c2ecf20Sopenharmony_ci page_end = page_start + bp->flash_info->page_size; 45888c2ecf20Sopenharmony_ci /* Find the data_start addr */ 45898c2ecf20Sopenharmony_ci data_start = (written == 0) ? offset32 : page_start; 45908c2ecf20Sopenharmony_ci /* Find the data_end addr */ 45918c2ecf20Sopenharmony_ci data_end = (page_end > offset32 + len32) ? 45928c2ecf20Sopenharmony_ci (offset32 + len32) : page_end; 45938c2ecf20Sopenharmony_ci 45948c2ecf20Sopenharmony_ci /* Request access to the flash interface. */ 45958c2ecf20Sopenharmony_ci if ((rc = bnx2_acquire_nvram_lock(bp)) != 0) 45968c2ecf20Sopenharmony_ci goto nvram_write_end; 45978c2ecf20Sopenharmony_ci 45988c2ecf20Sopenharmony_ci /* Enable access to flash interface */ 45998c2ecf20Sopenharmony_ci bnx2_enable_nvram_access(bp); 46008c2ecf20Sopenharmony_ci 46018c2ecf20Sopenharmony_ci cmd_flags = BNX2_NVM_COMMAND_FIRST; 46028c2ecf20Sopenharmony_ci if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) { 46038c2ecf20Sopenharmony_ci int j; 46048c2ecf20Sopenharmony_ci 46058c2ecf20Sopenharmony_ci /* Read the whole page into the buffer 46068c2ecf20Sopenharmony_ci * (non-buffer flash only) */ 46078c2ecf20Sopenharmony_ci for (j = 0; j < bp->flash_info->page_size; j += 4) { 46088c2ecf20Sopenharmony_ci if (j == (bp->flash_info->page_size - 4)) { 46098c2ecf20Sopenharmony_ci cmd_flags |= BNX2_NVM_COMMAND_LAST; 46108c2ecf20Sopenharmony_ci } 46118c2ecf20Sopenharmony_ci rc = bnx2_nvram_read_dword(bp, 46128c2ecf20Sopenharmony_ci page_start + j, 46138c2ecf20Sopenharmony_ci &flash_buffer[j], 46148c2ecf20Sopenharmony_ci cmd_flags); 46158c2ecf20Sopenharmony_ci 46168c2ecf20Sopenharmony_ci if (rc) 46178c2ecf20Sopenharmony_ci goto nvram_write_end; 46188c2ecf20Sopenharmony_ci 46198c2ecf20Sopenharmony_ci cmd_flags = 0; 46208c2ecf20Sopenharmony_ci } 46218c2ecf20Sopenharmony_ci } 46228c2ecf20Sopenharmony_ci 46238c2ecf20Sopenharmony_ci /* Enable writes to flash interface (unlock write-protect) */ 46248c2ecf20Sopenharmony_ci if ((rc = bnx2_enable_nvram_write(bp)) != 0) 46258c2ecf20Sopenharmony_ci goto nvram_write_end; 46268c2ecf20Sopenharmony_ci 46278c2ecf20Sopenharmony_ci /* Loop to write back the buffer data from page_start to 46288c2ecf20Sopenharmony_ci * data_start */ 46298c2ecf20Sopenharmony_ci i = 0; 46308c2ecf20Sopenharmony_ci if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) { 46318c2ecf20Sopenharmony_ci /* Erase the page */ 46328c2ecf20Sopenharmony_ci if ((rc = bnx2_nvram_erase_page(bp, page_start)) != 0) 46338c2ecf20Sopenharmony_ci goto nvram_write_end; 46348c2ecf20Sopenharmony_ci 46358c2ecf20Sopenharmony_ci /* Re-enable the write again for the actual write */ 46368c2ecf20Sopenharmony_ci bnx2_enable_nvram_write(bp); 46378c2ecf20Sopenharmony_ci 46388c2ecf20Sopenharmony_ci for (addr = page_start; addr < data_start; 46398c2ecf20Sopenharmony_ci addr += 4, i += 4) { 46408c2ecf20Sopenharmony_ci 46418c2ecf20Sopenharmony_ci rc = bnx2_nvram_write_dword(bp, addr, 46428c2ecf20Sopenharmony_ci &flash_buffer[i], cmd_flags); 46438c2ecf20Sopenharmony_ci 46448c2ecf20Sopenharmony_ci if (rc != 0) 46458c2ecf20Sopenharmony_ci goto nvram_write_end; 46468c2ecf20Sopenharmony_ci 46478c2ecf20Sopenharmony_ci cmd_flags = 0; 46488c2ecf20Sopenharmony_ci } 46498c2ecf20Sopenharmony_ci } 46508c2ecf20Sopenharmony_ci 46518c2ecf20Sopenharmony_ci /* Loop to write the new data from data_start to data_end */ 46528c2ecf20Sopenharmony_ci for (addr = data_start; addr < data_end; addr += 4, i += 4) { 46538c2ecf20Sopenharmony_ci if ((addr == page_end - 4) || 46548c2ecf20Sopenharmony_ci ((bp->flash_info->flags & BNX2_NV_BUFFERED) && 46558c2ecf20Sopenharmony_ci (addr == data_end - 4))) { 46568c2ecf20Sopenharmony_ci 46578c2ecf20Sopenharmony_ci cmd_flags |= BNX2_NVM_COMMAND_LAST; 46588c2ecf20Sopenharmony_ci } 46598c2ecf20Sopenharmony_ci rc = bnx2_nvram_write_dword(bp, addr, buf, 46608c2ecf20Sopenharmony_ci cmd_flags); 46618c2ecf20Sopenharmony_ci 46628c2ecf20Sopenharmony_ci if (rc != 0) 46638c2ecf20Sopenharmony_ci goto nvram_write_end; 46648c2ecf20Sopenharmony_ci 46658c2ecf20Sopenharmony_ci cmd_flags = 0; 46668c2ecf20Sopenharmony_ci buf += 4; 46678c2ecf20Sopenharmony_ci } 46688c2ecf20Sopenharmony_ci 46698c2ecf20Sopenharmony_ci /* Loop to write back the buffer data from data_end 46708c2ecf20Sopenharmony_ci * to page_end */ 46718c2ecf20Sopenharmony_ci if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) { 46728c2ecf20Sopenharmony_ci for (addr = data_end; addr < page_end; 46738c2ecf20Sopenharmony_ci addr += 4, i += 4) { 46748c2ecf20Sopenharmony_ci 46758c2ecf20Sopenharmony_ci if (addr == page_end-4) { 46768c2ecf20Sopenharmony_ci cmd_flags = BNX2_NVM_COMMAND_LAST; 46778c2ecf20Sopenharmony_ci } 46788c2ecf20Sopenharmony_ci rc = bnx2_nvram_write_dword(bp, addr, 46798c2ecf20Sopenharmony_ci &flash_buffer[i], cmd_flags); 46808c2ecf20Sopenharmony_ci 46818c2ecf20Sopenharmony_ci if (rc != 0) 46828c2ecf20Sopenharmony_ci goto nvram_write_end; 46838c2ecf20Sopenharmony_ci 46848c2ecf20Sopenharmony_ci cmd_flags = 0; 46858c2ecf20Sopenharmony_ci } 46868c2ecf20Sopenharmony_ci } 46878c2ecf20Sopenharmony_ci 46888c2ecf20Sopenharmony_ci /* Disable writes to flash interface (lock write-protect) */ 46898c2ecf20Sopenharmony_ci bnx2_disable_nvram_write(bp); 46908c2ecf20Sopenharmony_ci 46918c2ecf20Sopenharmony_ci /* Disable access to flash interface */ 46928c2ecf20Sopenharmony_ci bnx2_disable_nvram_access(bp); 46938c2ecf20Sopenharmony_ci bnx2_release_nvram_lock(bp); 46948c2ecf20Sopenharmony_ci 46958c2ecf20Sopenharmony_ci /* Increment written */ 46968c2ecf20Sopenharmony_ci written += data_end - data_start; 46978c2ecf20Sopenharmony_ci } 46988c2ecf20Sopenharmony_ci 46998c2ecf20Sopenharmony_cinvram_write_end: 47008c2ecf20Sopenharmony_ci kfree(flash_buffer); 47018c2ecf20Sopenharmony_ci kfree(align_buf); 47028c2ecf20Sopenharmony_ci return rc; 47038c2ecf20Sopenharmony_ci} 47048c2ecf20Sopenharmony_ci 47058c2ecf20Sopenharmony_cistatic void 47068c2ecf20Sopenharmony_cibnx2_init_fw_cap(struct bnx2 *bp) 47078c2ecf20Sopenharmony_ci{ 47088c2ecf20Sopenharmony_ci u32 val, sig = 0; 47098c2ecf20Sopenharmony_ci 47108c2ecf20Sopenharmony_ci bp->phy_flags &= ~BNX2_PHY_FLAG_REMOTE_PHY_CAP; 47118c2ecf20Sopenharmony_ci bp->flags &= ~BNX2_FLAG_CAN_KEEP_VLAN; 47128c2ecf20Sopenharmony_ci 47138c2ecf20Sopenharmony_ci if (!(bp->flags & BNX2_FLAG_ASF_ENABLE)) 47148c2ecf20Sopenharmony_ci bp->flags |= BNX2_FLAG_CAN_KEEP_VLAN; 47158c2ecf20Sopenharmony_ci 47168c2ecf20Sopenharmony_ci val = bnx2_shmem_rd(bp, BNX2_FW_CAP_MB); 47178c2ecf20Sopenharmony_ci if ((val & BNX2_FW_CAP_SIGNATURE_MASK) != BNX2_FW_CAP_SIGNATURE) 47188c2ecf20Sopenharmony_ci return; 47198c2ecf20Sopenharmony_ci 47208c2ecf20Sopenharmony_ci if ((val & BNX2_FW_CAP_CAN_KEEP_VLAN) == BNX2_FW_CAP_CAN_KEEP_VLAN) { 47218c2ecf20Sopenharmony_ci bp->flags |= BNX2_FLAG_CAN_KEEP_VLAN; 47228c2ecf20Sopenharmony_ci sig |= BNX2_DRV_ACK_CAP_SIGNATURE | BNX2_FW_CAP_CAN_KEEP_VLAN; 47238c2ecf20Sopenharmony_ci } 47248c2ecf20Sopenharmony_ci 47258c2ecf20Sopenharmony_ci if ((bp->phy_flags & BNX2_PHY_FLAG_SERDES) && 47268c2ecf20Sopenharmony_ci (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE)) { 47278c2ecf20Sopenharmony_ci u32 link; 47288c2ecf20Sopenharmony_ci 47298c2ecf20Sopenharmony_ci bp->phy_flags |= BNX2_PHY_FLAG_REMOTE_PHY_CAP; 47308c2ecf20Sopenharmony_ci 47318c2ecf20Sopenharmony_ci link = bnx2_shmem_rd(bp, BNX2_LINK_STATUS); 47328c2ecf20Sopenharmony_ci if (link & BNX2_LINK_STATUS_SERDES_LINK) 47338c2ecf20Sopenharmony_ci bp->phy_port = PORT_FIBRE; 47348c2ecf20Sopenharmony_ci else 47358c2ecf20Sopenharmony_ci bp->phy_port = PORT_TP; 47368c2ecf20Sopenharmony_ci 47378c2ecf20Sopenharmony_ci sig |= BNX2_DRV_ACK_CAP_SIGNATURE | 47388c2ecf20Sopenharmony_ci BNX2_FW_CAP_REMOTE_PHY_CAPABLE; 47398c2ecf20Sopenharmony_ci } 47408c2ecf20Sopenharmony_ci 47418c2ecf20Sopenharmony_ci if (netif_running(bp->dev) && sig) 47428c2ecf20Sopenharmony_ci bnx2_shmem_wr(bp, BNX2_DRV_ACK_CAP_MB, sig); 47438c2ecf20Sopenharmony_ci} 47448c2ecf20Sopenharmony_ci 47458c2ecf20Sopenharmony_cistatic void 47468c2ecf20Sopenharmony_cibnx2_setup_msix_tbl(struct bnx2 *bp) 47478c2ecf20Sopenharmony_ci{ 47488c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_PCI_GRC_WINDOW_ADDR, BNX2_PCI_GRC_WINDOW_ADDR_SEP_WIN); 47498c2ecf20Sopenharmony_ci 47508c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_PCI_GRC_WINDOW2_ADDR, BNX2_MSIX_TABLE_ADDR); 47518c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_PCI_GRC_WINDOW3_ADDR, BNX2_MSIX_PBA_ADDR); 47528c2ecf20Sopenharmony_ci} 47538c2ecf20Sopenharmony_ci 47548c2ecf20Sopenharmony_cistatic void 47558c2ecf20Sopenharmony_cibnx2_wait_dma_complete(struct bnx2 *bp) 47568c2ecf20Sopenharmony_ci{ 47578c2ecf20Sopenharmony_ci u32 val; 47588c2ecf20Sopenharmony_ci int i; 47598c2ecf20Sopenharmony_ci 47608c2ecf20Sopenharmony_ci /* 47618c2ecf20Sopenharmony_ci * Wait for the current PCI transaction to complete before 47628c2ecf20Sopenharmony_ci * issuing a reset. 47638c2ecf20Sopenharmony_ci */ 47648c2ecf20Sopenharmony_ci if ((BNX2_CHIP(bp) == BNX2_CHIP_5706) || 47658c2ecf20Sopenharmony_ci (BNX2_CHIP(bp) == BNX2_CHIP_5708)) { 47668c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_MISC_ENABLE_CLR_BITS, 47678c2ecf20Sopenharmony_ci BNX2_MISC_ENABLE_CLR_BITS_TX_DMA_ENABLE | 47688c2ecf20Sopenharmony_ci BNX2_MISC_ENABLE_CLR_BITS_DMA_ENGINE_ENABLE | 47698c2ecf20Sopenharmony_ci BNX2_MISC_ENABLE_CLR_BITS_RX_DMA_ENABLE | 47708c2ecf20Sopenharmony_ci BNX2_MISC_ENABLE_CLR_BITS_HOST_COALESCE_ENABLE); 47718c2ecf20Sopenharmony_ci val = BNX2_RD(bp, BNX2_MISC_ENABLE_CLR_BITS); 47728c2ecf20Sopenharmony_ci udelay(5); 47738c2ecf20Sopenharmony_ci } else { /* 5709 */ 47748c2ecf20Sopenharmony_ci val = BNX2_RD(bp, BNX2_MISC_NEW_CORE_CTL); 47758c2ecf20Sopenharmony_ci val &= ~BNX2_MISC_NEW_CORE_CTL_DMA_ENABLE; 47768c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_MISC_NEW_CORE_CTL, val); 47778c2ecf20Sopenharmony_ci val = BNX2_RD(bp, BNX2_MISC_NEW_CORE_CTL); 47788c2ecf20Sopenharmony_ci 47798c2ecf20Sopenharmony_ci for (i = 0; i < 100; i++) { 47808c2ecf20Sopenharmony_ci msleep(1); 47818c2ecf20Sopenharmony_ci val = BNX2_RD(bp, BNX2_PCICFG_DEVICE_CONTROL); 47828c2ecf20Sopenharmony_ci if (!(val & BNX2_PCICFG_DEVICE_STATUS_NO_PEND)) 47838c2ecf20Sopenharmony_ci break; 47848c2ecf20Sopenharmony_ci } 47858c2ecf20Sopenharmony_ci } 47868c2ecf20Sopenharmony_ci 47878c2ecf20Sopenharmony_ci return; 47888c2ecf20Sopenharmony_ci} 47898c2ecf20Sopenharmony_ci 47908c2ecf20Sopenharmony_ci 47918c2ecf20Sopenharmony_cistatic int 47928c2ecf20Sopenharmony_cibnx2_reset_chip(struct bnx2 *bp, u32 reset_code) 47938c2ecf20Sopenharmony_ci{ 47948c2ecf20Sopenharmony_ci u32 val; 47958c2ecf20Sopenharmony_ci int i, rc = 0; 47968c2ecf20Sopenharmony_ci u8 old_port; 47978c2ecf20Sopenharmony_ci 47988c2ecf20Sopenharmony_ci /* Wait for the current PCI transaction to complete before 47998c2ecf20Sopenharmony_ci * issuing a reset. */ 48008c2ecf20Sopenharmony_ci bnx2_wait_dma_complete(bp); 48018c2ecf20Sopenharmony_ci 48028c2ecf20Sopenharmony_ci /* Wait for the firmware to tell us it is ok to issue a reset. */ 48038c2ecf20Sopenharmony_ci bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT0 | reset_code, 1, 1); 48048c2ecf20Sopenharmony_ci 48058c2ecf20Sopenharmony_ci /* Deposit a driver reset signature so the firmware knows that 48068c2ecf20Sopenharmony_ci * this is a soft reset. */ 48078c2ecf20Sopenharmony_ci bnx2_shmem_wr(bp, BNX2_DRV_RESET_SIGNATURE, 48088c2ecf20Sopenharmony_ci BNX2_DRV_RESET_SIGNATURE_MAGIC); 48098c2ecf20Sopenharmony_ci 48108c2ecf20Sopenharmony_ci /* Do a dummy read to force the chip to complete all current transaction 48118c2ecf20Sopenharmony_ci * before we issue a reset. */ 48128c2ecf20Sopenharmony_ci val = BNX2_RD(bp, BNX2_MISC_ID); 48138c2ecf20Sopenharmony_ci 48148c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5709) { 48158c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_MISC_COMMAND, BNX2_MISC_COMMAND_SW_RESET); 48168c2ecf20Sopenharmony_ci BNX2_RD(bp, BNX2_MISC_COMMAND); 48178c2ecf20Sopenharmony_ci udelay(5); 48188c2ecf20Sopenharmony_ci 48198c2ecf20Sopenharmony_ci val = BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA | 48208c2ecf20Sopenharmony_ci BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP; 48218c2ecf20Sopenharmony_ci 48228c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_PCICFG_MISC_CONFIG, val); 48238c2ecf20Sopenharmony_ci 48248c2ecf20Sopenharmony_ci } else { 48258c2ecf20Sopenharmony_ci val = BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ | 48268c2ecf20Sopenharmony_ci BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA | 48278c2ecf20Sopenharmony_ci BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP; 48288c2ecf20Sopenharmony_ci 48298c2ecf20Sopenharmony_ci /* Chip reset. */ 48308c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_PCICFG_MISC_CONFIG, val); 48318c2ecf20Sopenharmony_ci 48328c2ecf20Sopenharmony_ci /* Reading back any register after chip reset will hang the 48338c2ecf20Sopenharmony_ci * bus on 5706 A0 and A1. The msleep below provides plenty 48348c2ecf20Sopenharmony_ci * of margin for write posting. 48358c2ecf20Sopenharmony_ci */ 48368c2ecf20Sopenharmony_ci if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) || 48378c2ecf20Sopenharmony_ci (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1)) 48388c2ecf20Sopenharmony_ci msleep(20); 48398c2ecf20Sopenharmony_ci 48408c2ecf20Sopenharmony_ci /* Reset takes approximate 30 usec */ 48418c2ecf20Sopenharmony_ci for (i = 0; i < 10; i++) { 48428c2ecf20Sopenharmony_ci val = BNX2_RD(bp, BNX2_PCICFG_MISC_CONFIG); 48438c2ecf20Sopenharmony_ci if ((val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ | 48448c2ecf20Sopenharmony_ci BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) == 0) 48458c2ecf20Sopenharmony_ci break; 48468c2ecf20Sopenharmony_ci udelay(10); 48478c2ecf20Sopenharmony_ci } 48488c2ecf20Sopenharmony_ci 48498c2ecf20Sopenharmony_ci if (val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ | 48508c2ecf20Sopenharmony_ci BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) { 48518c2ecf20Sopenharmony_ci pr_err("Chip reset did not complete\n"); 48528c2ecf20Sopenharmony_ci return -EBUSY; 48538c2ecf20Sopenharmony_ci } 48548c2ecf20Sopenharmony_ci } 48558c2ecf20Sopenharmony_ci 48568c2ecf20Sopenharmony_ci /* Make sure byte swapping is properly configured. */ 48578c2ecf20Sopenharmony_ci val = BNX2_RD(bp, BNX2_PCI_SWAP_DIAG0); 48588c2ecf20Sopenharmony_ci if (val != 0x01020304) { 48598c2ecf20Sopenharmony_ci pr_err("Chip not in correct endian mode\n"); 48608c2ecf20Sopenharmony_ci return -ENODEV; 48618c2ecf20Sopenharmony_ci } 48628c2ecf20Sopenharmony_ci 48638c2ecf20Sopenharmony_ci /* Wait for the firmware to finish its initialization. */ 48648c2ecf20Sopenharmony_ci rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT1 | reset_code, 1, 0); 48658c2ecf20Sopenharmony_ci if (rc) 48668c2ecf20Sopenharmony_ci return rc; 48678c2ecf20Sopenharmony_ci 48688c2ecf20Sopenharmony_ci spin_lock_bh(&bp->phy_lock); 48698c2ecf20Sopenharmony_ci old_port = bp->phy_port; 48708c2ecf20Sopenharmony_ci bnx2_init_fw_cap(bp); 48718c2ecf20Sopenharmony_ci if ((bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) && 48728c2ecf20Sopenharmony_ci old_port != bp->phy_port) 48738c2ecf20Sopenharmony_ci bnx2_set_default_remote_link(bp); 48748c2ecf20Sopenharmony_ci spin_unlock_bh(&bp->phy_lock); 48758c2ecf20Sopenharmony_ci 48768c2ecf20Sopenharmony_ci if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) { 48778c2ecf20Sopenharmony_ci /* Adjust the voltage regular to two steps lower. The default 48788c2ecf20Sopenharmony_ci * of this register is 0x0000000e. */ 48798c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_MISC_VREG_CONTROL, 0x000000fa); 48808c2ecf20Sopenharmony_ci 48818c2ecf20Sopenharmony_ci /* Remove bad rbuf memory from the free pool. */ 48828c2ecf20Sopenharmony_ci rc = bnx2_alloc_bad_rbuf(bp); 48838c2ecf20Sopenharmony_ci } 48848c2ecf20Sopenharmony_ci 48858c2ecf20Sopenharmony_ci if (bp->flags & BNX2_FLAG_USING_MSIX) { 48868c2ecf20Sopenharmony_ci bnx2_setup_msix_tbl(bp); 48878c2ecf20Sopenharmony_ci /* Prevent MSIX table reads and write from timing out */ 48888c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_MISC_ECO_HW_CTL, 48898c2ecf20Sopenharmony_ci BNX2_MISC_ECO_HW_CTL_LARGE_GRC_TMOUT_EN); 48908c2ecf20Sopenharmony_ci } 48918c2ecf20Sopenharmony_ci 48928c2ecf20Sopenharmony_ci return rc; 48938c2ecf20Sopenharmony_ci} 48948c2ecf20Sopenharmony_ci 48958c2ecf20Sopenharmony_cistatic int 48968c2ecf20Sopenharmony_cibnx2_init_chip(struct bnx2 *bp) 48978c2ecf20Sopenharmony_ci{ 48988c2ecf20Sopenharmony_ci u32 val, mtu; 48998c2ecf20Sopenharmony_ci int rc, i; 49008c2ecf20Sopenharmony_ci 49018c2ecf20Sopenharmony_ci /* Make sure the interrupt is not active. */ 49028c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_MASK_INT); 49038c2ecf20Sopenharmony_ci 49048c2ecf20Sopenharmony_ci val = BNX2_DMA_CONFIG_DATA_BYTE_SWAP | 49058c2ecf20Sopenharmony_ci BNX2_DMA_CONFIG_DATA_WORD_SWAP | 49068c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 49078c2ecf20Sopenharmony_ci BNX2_DMA_CONFIG_CNTL_BYTE_SWAP | 49088c2ecf20Sopenharmony_ci#endif 49098c2ecf20Sopenharmony_ci BNX2_DMA_CONFIG_CNTL_WORD_SWAP | 49108c2ecf20Sopenharmony_ci DMA_READ_CHANS << 12 | 49118c2ecf20Sopenharmony_ci DMA_WRITE_CHANS << 16; 49128c2ecf20Sopenharmony_ci 49138c2ecf20Sopenharmony_ci val |= (0x2 << 20) | (1 << 11); 49148c2ecf20Sopenharmony_ci 49158c2ecf20Sopenharmony_ci if ((bp->flags & BNX2_FLAG_PCIX) && (bp->bus_speed_mhz == 133)) 49168c2ecf20Sopenharmony_ci val |= (1 << 23); 49178c2ecf20Sopenharmony_ci 49188c2ecf20Sopenharmony_ci if ((BNX2_CHIP(bp) == BNX2_CHIP_5706) && 49198c2ecf20Sopenharmony_ci (BNX2_CHIP_ID(bp) != BNX2_CHIP_ID_5706_A0) && 49208c2ecf20Sopenharmony_ci !(bp->flags & BNX2_FLAG_PCIX)) 49218c2ecf20Sopenharmony_ci val |= BNX2_DMA_CONFIG_CNTL_PING_PONG_DMA; 49228c2ecf20Sopenharmony_ci 49238c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_DMA_CONFIG, val); 49248c2ecf20Sopenharmony_ci 49258c2ecf20Sopenharmony_ci if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) { 49268c2ecf20Sopenharmony_ci val = BNX2_RD(bp, BNX2_TDMA_CONFIG); 49278c2ecf20Sopenharmony_ci val |= BNX2_TDMA_CONFIG_ONE_DMA; 49288c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_TDMA_CONFIG, val); 49298c2ecf20Sopenharmony_ci } 49308c2ecf20Sopenharmony_ci 49318c2ecf20Sopenharmony_ci if (bp->flags & BNX2_FLAG_PCIX) { 49328c2ecf20Sopenharmony_ci u16 val16; 49338c2ecf20Sopenharmony_ci 49348c2ecf20Sopenharmony_ci pci_read_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD, 49358c2ecf20Sopenharmony_ci &val16); 49368c2ecf20Sopenharmony_ci pci_write_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD, 49378c2ecf20Sopenharmony_ci val16 & ~PCI_X_CMD_ERO); 49388c2ecf20Sopenharmony_ci } 49398c2ecf20Sopenharmony_ci 49408c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_MISC_ENABLE_SET_BITS, 49418c2ecf20Sopenharmony_ci BNX2_MISC_ENABLE_SET_BITS_HOST_COALESCE_ENABLE | 49428c2ecf20Sopenharmony_ci BNX2_MISC_ENABLE_STATUS_BITS_RX_V2P_ENABLE | 49438c2ecf20Sopenharmony_ci BNX2_MISC_ENABLE_STATUS_BITS_CONTEXT_ENABLE); 49448c2ecf20Sopenharmony_ci 49458c2ecf20Sopenharmony_ci /* Initialize context mapping and zero out the quick contexts. The 49468c2ecf20Sopenharmony_ci * context block must have already been enabled. */ 49478c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5709) { 49488c2ecf20Sopenharmony_ci rc = bnx2_init_5709_context(bp); 49498c2ecf20Sopenharmony_ci if (rc) 49508c2ecf20Sopenharmony_ci return rc; 49518c2ecf20Sopenharmony_ci } else 49528c2ecf20Sopenharmony_ci bnx2_init_context(bp); 49538c2ecf20Sopenharmony_ci 49548c2ecf20Sopenharmony_ci if ((rc = bnx2_init_cpus(bp)) != 0) 49558c2ecf20Sopenharmony_ci return rc; 49568c2ecf20Sopenharmony_ci 49578c2ecf20Sopenharmony_ci bnx2_init_nvram(bp); 49588c2ecf20Sopenharmony_ci 49598c2ecf20Sopenharmony_ci bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0); 49608c2ecf20Sopenharmony_ci 49618c2ecf20Sopenharmony_ci val = BNX2_RD(bp, BNX2_MQ_CONFIG); 49628c2ecf20Sopenharmony_ci val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE; 49638c2ecf20Sopenharmony_ci val |= BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_256; 49648c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5709) { 49658c2ecf20Sopenharmony_ci val |= BNX2_MQ_CONFIG_BIN_MQ_MODE; 49668c2ecf20Sopenharmony_ci if (BNX2_CHIP_REV(bp) == BNX2_CHIP_REV_Ax) 49678c2ecf20Sopenharmony_ci val |= BNX2_MQ_CONFIG_HALT_DIS; 49688c2ecf20Sopenharmony_ci } 49698c2ecf20Sopenharmony_ci 49708c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_MQ_CONFIG, val); 49718c2ecf20Sopenharmony_ci 49728c2ecf20Sopenharmony_ci val = 0x10000 + (MAX_CID_CNT * MB_KERNEL_CTX_SIZE); 49738c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_MQ_KNL_BYP_WIND_START, val); 49748c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_MQ_KNL_WIND_END, val); 49758c2ecf20Sopenharmony_ci 49768c2ecf20Sopenharmony_ci val = (BNX2_PAGE_BITS - 8) << 24; 49778c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_RV2P_CONFIG, val); 49788c2ecf20Sopenharmony_ci 49798c2ecf20Sopenharmony_ci /* Configure page size. */ 49808c2ecf20Sopenharmony_ci val = BNX2_RD(bp, BNX2_TBDR_CONFIG); 49818c2ecf20Sopenharmony_ci val &= ~BNX2_TBDR_CONFIG_PAGE_SIZE; 49828c2ecf20Sopenharmony_ci val |= (BNX2_PAGE_BITS - 8) << 24 | 0x40; 49838c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_TBDR_CONFIG, val); 49848c2ecf20Sopenharmony_ci 49858c2ecf20Sopenharmony_ci val = bp->mac_addr[0] + 49868c2ecf20Sopenharmony_ci (bp->mac_addr[1] << 8) + 49878c2ecf20Sopenharmony_ci (bp->mac_addr[2] << 16) + 49888c2ecf20Sopenharmony_ci bp->mac_addr[3] + 49898c2ecf20Sopenharmony_ci (bp->mac_addr[4] << 8) + 49908c2ecf20Sopenharmony_ci (bp->mac_addr[5] << 16); 49918c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_EMAC_BACKOFF_SEED, val); 49928c2ecf20Sopenharmony_ci 49938c2ecf20Sopenharmony_ci /* Program the MTU. Also include 4 bytes for CRC32. */ 49948c2ecf20Sopenharmony_ci mtu = bp->dev->mtu; 49958c2ecf20Sopenharmony_ci val = mtu + ETH_HLEN + ETH_FCS_LEN; 49968c2ecf20Sopenharmony_ci if (val > (MAX_ETHERNET_PACKET_SIZE + ETH_HLEN + 4)) 49978c2ecf20Sopenharmony_ci val |= BNX2_EMAC_RX_MTU_SIZE_JUMBO_ENA; 49988c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_EMAC_RX_MTU_SIZE, val); 49998c2ecf20Sopenharmony_ci 50008c2ecf20Sopenharmony_ci if (mtu < ETH_DATA_LEN) 50018c2ecf20Sopenharmony_ci mtu = ETH_DATA_LEN; 50028c2ecf20Sopenharmony_ci 50038c2ecf20Sopenharmony_ci bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG, BNX2_RBUF_CONFIG_VAL(mtu)); 50048c2ecf20Sopenharmony_ci bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG2, BNX2_RBUF_CONFIG2_VAL(mtu)); 50058c2ecf20Sopenharmony_ci bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG3, BNX2_RBUF_CONFIG3_VAL(mtu)); 50068c2ecf20Sopenharmony_ci 50078c2ecf20Sopenharmony_ci memset(bp->bnx2_napi[0].status_blk.msi, 0, bp->status_stats_size); 50088c2ecf20Sopenharmony_ci for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) 50098c2ecf20Sopenharmony_ci bp->bnx2_napi[i].last_status_idx = 0; 50108c2ecf20Sopenharmony_ci 50118c2ecf20Sopenharmony_ci bp->idle_chk_status_idx = 0xffff; 50128c2ecf20Sopenharmony_ci 50138c2ecf20Sopenharmony_ci /* Set up how to generate a link change interrupt. */ 50148c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK); 50158c2ecf20Sopenharmony_ci 50168c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_HC_STATUS_ADDR_L, 50178c2ecf20Sopenharmony_ci (u64) bp->status_blk_mapping & 0xffffffff); 50188c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_HC_STATUS_ADDR_H, (u64) bp->status_blk_mapping >> 32); 50198c2ecf20Sopenharmony_ci 50208c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_HC_STATISTICS_ADDR_L, 50218c2ecf20Sopenharmony_ci (u64) bp->stats_blk_mapping & 0xffffffff); 50228c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_HC_STATISTICS_ADDR_H, 50238c2ecf20Sopenharmony_ci (u64) bp->stats_blk_mapping >> 32); 50248c2ecf20Sopenharmony_ci 50258c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_HC_TX_QUICK_CONS_TRIP, 50268c2ecf20Sopenharmony_ci (bp->tx_quick_cons_trip_int << 16) | bp->tx_quick_cons_trip); 50278c2ecf20Sopenharmony_ci 50288c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_HC_RX_QUICK_CONS_TRIP, 50298c2ecf20Sopenharmony_ci (bp->rx_quick_cons_trip_int << 16) | bp->rx_quick_cons_trip); 50308c2ecf20Sopenharmony_ci 50318c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_HC_COMP_PROD_TRIP, 50328c2ecf20Sopenharmony_ci (bp->comp_prod_trip_int << 16) | bp->comp_prod_trip); 50338c2ecf20Sopenharmony_ci 50348c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_HC_TX_TICKS, (bp->tx_ticks_int << 16) | bp->tx_ticks); 50358c2ecf20Sopenharmony_ci 50368c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_HC_RX_TICKS, (bp->rx_ticks_int << 16) | bp->rx_ticks); 50378c2ecf20Sopenharmony_ci 50388c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_HC_COM_TICKS, 50398c2ecf20Sopenharmony_ci (bp->com_ticks_int << 16) | bp->com_ticks); 50408c2ecf20Sopenharmony_ci 50418c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_HC_CMD_TICKS, 50428c2ecf20Sopenharmony_ci (bp->cmd_ticks_int << 16) | bp->cmd_ticks); 50438c2ecf20Sopenharmony_ci 50448c2ecf20Sopenharmony_ci if (bp->flags & BNX2_FLAG_BROKEN_STATS) 50458c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_HC_STATS_TICKS, 0); 50468c2ecf20Sopenharmony_ci else 50478c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks); 50488c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_HC_STAT_COLLECT_TICKS, 0xbb8); /* 3ms */ 50498c2ecf20Sopenharmony_ci 50508c2ecf20Sopenharmony_ci if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1) 50518c2ecf20Sopenharmony_ci val = BNX2_HC_CONFIG_COLLECT_STATS; 50528c2ecf20Sopenharmony_ci else { 50538c2ecf20Sopenharmony_ci val = BNX2_HC_CONFIG_RX_TMR_MODE | BNX2_HC_CONFIG_TX_TMR_MODE | 50548c2ecf20Sopenharmony_ci BNX2_HC_CONFIG_COLLECT_STATS; 50558c2ecf20Sopenharmony_ci } 50568c2ecf20Sopenharmony_ci 50578c2ecf20Sopenharmony_ci if (bp->flags & BNX2_FLAG_USING_MSIX) { 50588c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_HC_MSIX_BIT_VECTOR, 50598c2ecf20Sopenharmony_ci BNX2_HC_MSIX_BIT_VECTOR_VAL); 50608c2ecf20Sopenharmony_ci 50618c2ecf20Sopenharmony_ci val |= BNX2_HC_CONFIG_SB_ADDR_INC_128B; 50628c2ecf20Sopenharmony_ci } 50638c2ecf20Sopenharmony_ci 50648c2ecf20Sopenharmony_ci if (bp->flags & BNX2_FLAG_ONE_SHOT_MSI) 50658c2ecf20Sopenharmony_ci val |= BNX2_HC_CONFIG_ONE_SHOT | BNX2_HC_CONFIG_USE_INT_PARAM; 50668c2ecf20Sopenharmony_ci 50678c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_HC_CONFIG, val); 50688c2ecf20Sopenharmony_ci 50698c2ecf20Sopenharmony_ci if (bp->rx_ticks < 25) 50708c2ecf20Sopenharmony_ci bnx2_reg_wr_ind(bp, BNX2_FW_RX_LOW_LATENCY, 1); 50718c2ecf20Sopenharmony_ci else 50728c2ecf20Sopenharmony_ci bnx2_reg_wr_ind(bp, BNX2_FW_RX_LOW_LATENCY, 0); 50738c2ecf20Sopenharmony_ci 50748c2ecf20Sopenharmony_ci for (i = 1; i < bp->irq_nvecs; i++) { 50758c2ecf20Sopenharmony_ci u32 base = ((i - 1) * BNX2_HC_SB_CONFIG_SIZE) + 50768c2ecf20Sopenharmony_ci BNX2_HC_SB_CONFIG_1; 50778c2ecf20Sopenharmony_ci 50788c2ecf20Sopenharmony_ci BNX2_WR(bp, base, 50798c2ecf20Sopenharmony_ci BNX2_HC_SB_CONFIG_1_TX_TMR_MODE | 50808c2ecf20Sopenharmony_ci BNX2_HC_SB_CONFIG_1_RX_TMR_MODE | 50818c2ecf20Sopenharmony_ci BNX2_HC_SB_CONFIG_1_ONE_SHOT); 50828c2ecf20Sopenharmony_ci 50838c2ecf20Sopenharmony_ci BNX2_WR(bp, base + BNX2_HC_TX_QUICK_CONS_TRIP_OFF, 50848c2ecf20Sopenharmony_ci (bp->tx_quick_cons_trip_int << 16) | 50858c2ecf20Sopenharmony_ci bp->tx_quick_cons_trip); 50868c2ecf20Sopenharmony_ci 50878c2ecf20Sopenharmony_ci BNX2_WR(bp, base + BNX2_HC_TX_TICKS_OFF, 50888c2ecf20Sopenharmony_ci (bp->tx_ticks_int << 16) | bp->tx_ticks); 50898c2ecf20Sopenharmony_ci 50908c2ecf20Sopenharmony_ci BNX2_WR(bp, base + BNX2_HC_RX_QUICK_CONS_TRIP_OFF, 50918c2ecf20Sopenharmony_ci (bp->rx_quick_cons_trip_int << 16) | 50928c2ecf20Sopenharmony_ci bp->rx_quick_cons_trip); 50938c2ecf20Sopenharmony_ci 50948c2ecf20Sopenharmony_ci BNX2_WR(bp, base + BNX2_HC_RX_TICKS_OFF, 50958c2ecf20Sopenharmony_ci (bp->rx_ticks_int << 16) | bp->rx_ticks); 50968c2ecf20Sopenharmony_ci } 50978c2ecf20Sopenharmony_ci 50988c2ecf20Sopenharmony_ci /* Clear internal stats counters. */ 50998c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_HC_COMMAND, BNX2_HC_COMMAND_CLR_STAT_NOW); 51008c2ecf20Sopenharmony_ci 51018c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_EVENTS); 51028c2ecf20Sopenharmony_ci 51038c2ecf20Sopenharmony_ci /* Initialize the receive filter. */ 51048c2ecf20Sopenharmony_ci bnx2_set_rx_mode(bp->dev); 51058c2ecf20Sopenharmony_ci 51068c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5709) { 51078c2ecf20Sopenharmony_ci val = BNX2_RD(bp, BNX2_MISC_NEW_CORE_CTL); 51088c2ecf20Sopenharmony_ci val |= BNX2_MISC_NEW_CORE_CTL_DMA_ENABLE; 51098c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_MISC_NEW_CORE_CTL, val); 51108c2ecf20Sopenharmony_ci } 51118c2ecf20Sopenharmony_ci rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT2 | BNX2_DRV_MSG_CODE_RESET, 51128c2ecf20Sopenharmony_ci 1, 0); 51138c2ecf20Sopenharmony_ci 51148c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_MISC_ENABLE_SET_BITS, BNX2_MISC_ENABLE_DEFAULT); 51158c2ecf20Sopenharmony_ci BNX2_RD(bp, BNX2_MISC_ENABLE_SET_BITS); 51168c2ecf20Sopenharmony_ci 51178c2ecf20Sopenharmony_ci udelay(20); 51188c2ecf20Sopenharmony_ci 51198c2ecf20Sopenharmony_ci bp->hc_cmd = BNX2_RD(bp, BNX2_HC_COMMAND); 51208c2ecf20Sopenharmony_ci 51218c2ecf20Sopenharmony_ci return rc; 51228c2ecf20Sopenharmony_ci} 51238c2ecf20Sopenharmony_ci 51248c2ecf20Sopenharmony_cistatic void 51258c2ecf20Sopenharmony_cibnx2_clear_ring_states(struct bnx2 *bp) 51268c2ecf20Sopenharmony_ci{ 51278c2ecf20Sopenharmony_ci struct bnx2_napi *bnapi; 51288c2ecf20Sopenharmony_ci struct bnx2_tx_ring_info *txr; 51298c2ecf20Sopenharmony_ci struct bnx2_rx_ring_info *rxr; 51308c2ecf20Sopenharmony_ci int i; 51318c2ecf20Sopenharmony_ci 51328c2ecf20Sopenharmony_ci for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) { 51338c2ecf20Sopenharmony_ci bnapi = &bp->bnx2_napi[i]; 51348c2ecf20Sopenharmony_ci txr = &bnapi->tx_ring; 51358c2ecf20Sopenharmony_ci rxr = &bnapi->rx_ring; 51368c2ecf20Sopenharmony_ci 51378c2ecf20Sopenharmony_ci txr->tx_cons = 0; 51388c2ecf20Sopenharmony_ci txr->hw_tx_cons = 0; 51398c2ecf20Sopenharmony_ci rxr->rx_prod_bseq = 0; 51408c2ecf20Sopenharmony_ci rxr->rx_prod = 0; 51418c2ecf20Sopenharmony_ci rxr->rx_cons = 0; 51428c2ecf20Sopenharmony_ci rxr->rx_pg_prod = 0; 51438c2ecf20Sopenharmony_ci rxr->rx_pg_cons = 0; 51448c2ecf20Sopenharmony_ci } 51458c2ecf20Sopenharmony_ci} 51468c2ecf20Sopenharmony_ci 51478c2ecf20Sopenharmony_cistatic void 51488c2ecf20Sopenharmony_cibnx2_init_tx_context(struct bnx2 *bp, u32 cid, struct bnx2_tx_ring_info *txr) 51498c2ecf20Sopenharmony_ci{ 51508c2ecf20Sopenharmony_ci u32 val, offset0, offset1, offset2, offset3; 51518c2ecf20Sopenharmony_ci u32 cid_addr = GET_CID_ADDR(cid); 51528c2ecf20Sopenharmony_ci 51538c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5709) { 51548c2ecf20Sopenharmony_ci offset0 = BNX2_L2CTX_TYPE_XI; 51558c2ecf20Sopenharmony_ci offset1 = BNX2_L2CTX_CMD_TYPE_XI; 51568c2ecf20Sopenharmony_ci offset2 = BNX2_L2CTX_TBDR_BHADDR_HI_XI; 51578c2ecf20Sopenharmony_ci offset3 = BNX2_L2CTX_TBDR_BHADDR_LO_XI; 51588c2ecf20Sopenharmony_ci } else { 51598c2ecf20Sopenharmony_ci offset0 = BNX2_L2CTX_TYPE; 51608c2ecf20Sopenharmony_ci offset1 = BNX2_L2CTX_CMD_TYPE; 51618c2ecf20Sopenharmony_ci offset2 = BNX2_L2CTX_TBDR_BHADDR_HI; 51628c2ecf20Sopenharmony_ci offset3 = BNX2_L2CTX_TBDR_BHADDR_LO; 51638c2ecf20Sopenharmony_ci } 51648c2ecf20Sopenharmony_ci val = BNX2_L2CTX_TYPE_TYPE_L2 | BNX2_L2CTX_TYPE_SIZE_L2; 51658c2ecf20Sopenharmony_ci bnx2_ctx_wr(bp, cid_addr, offset0, val); 51668c2ecf20Sopenharmony_ci 51678c2ecf20Sopenharmony_ci val = BNX2_L2CTX_CMD_TYPE_TYPE_L2 | (8 << 16); 51688c2ecf20Sopenharmony_ci bnx2_ctx_wr(bp, cid_addr, offset1, val); 51698c2ecf20Sopenharmony_ci 51708c2ecf20Sopenharmony_ci val = (u64) txr->tx_desc_mapping >> 32; 51718c2ecf20Sopenharmony_ci bnx2_ctx_wr(bp, cid_addr, offset2, val); 51728c2ecf20Sopenharmony_ci 51738c2ecf20Sopenharmony_ci val = (u64) txr->tx_desc_mapping & 0xffffffff; 51748c2ecf20Sopenharmony_ci bnx2_ctx_wr(bp, cid_addr, offset3, val); 51758c2ecf20Sopenharmony_ci} 51768c2ecf20Sopenharmony_ci 51778c2ecf20Sopenharmony_cistatic void 51788c2ecf20Sopenharmony_cibnx2_init_tx_ring(struct bnx2 *bp, int ring_num) 51798c2ecf20Sopenharmony_ci{ 51808c2ecf20Sopenharmony_ci struct bnx2_tx_bd *txbd; 51818c2ecf20Sopenharmony_ci u32 cid = TX_CID; 51828c2ecf20Sopenharmony_ci struct bnx2_napi *bnapi; 51838c2ecf20Sopenharmony_ci struct bnx2_tx_ring_info *txr; 51848c2ecf20Sopenharmony_ci 51858c2ecf20Sopenharmony_ci bnapi = &bp->bnx2_napi[ring_num]; 51868c2ecf20Sopenharmony_ci txr = &bnapi->tx_ring; 51878c2ecf20Sopenharmony_ci 51888c2ecf20Sopenharmony_ci if (ring_num == 0) 51898c2ecf20Sopenharmony_ci cid = TX_CID; 51908c2ecf20Sopenharmony_ci else 51918c2ecf20Sopenharmony_ci cid = TX_TSS_CID + ring_num - 1; 51928c2ecf20Sopenharmony_ci 51938c2ecf20Sopenharmony_ci bp->tx_wake_thresh = bp->tx_ring_size / 2; 51948c2ecf20Sopenharmony_ci 51958c2ecf20Sopenharmony_ci txbd = &txr->tx_desc_ring[BNX2_MAX_TX_DESC_CNT]; 51968c2ecf20Sopenharmony_ci 51978c2ecf20Sopenharmony_ci txbd->tx_bd_haddr_hi = (u64) txr->tx_desc_mapping >> 32; 51988c2ecf20Sopenharmony_ci txbd->tx_bd_haddr_lo = (u64) txr->tx_desc_mapping & 0xffffffff; 51998c2ecf20Sopenharmony_ci 52008c2ecf20Sopenharmony_ci txr->tx_prod = 0; 52018c2ecf20Sopenharmony_ci txr->tx_prod_bseq = 0; 52028c2ecf20Sopenharmony_ci 52038c2ecf20Sopenharmony_ci txr->tx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BIDX; 52048c2ecf20Sopenharmony_ci txr->tx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BSEQ; 52058c2ecf20Sopenharmony_ci 52068c2ecf20Sopenharmony_ci bnx2_init_tx_context(bp, cid, txr); 52078c2ecf20Sopenharmony_ci} 52088c2ecf20Sopenharmony_ci 52098c2ecf20Sopenharmony_cistatic void 52108c2ecf20Sopenharmony_cibnx2_init_rxbd_rings(struct bnx2_rx_bd *rx_ring[], dma_addr_t dma[], 52118c2ecf20Sopenharmony_ci u32 buf_size, int num_rings) 52128c2ecf20Sopenharmony_ci{ 52138c2ecf20Sopenharmony_ci int i; 52148c2ecf20Sopenharmony_ci struct bnx2_rx_bd *rxbd; 52158c2ecf20Sopenharmony_ci 52168c2ecf20Sopenharmony_ci for (i = 0; i < num_rings; i++) { 52178c2ecf20Sopenharmony_ci int j; 52188c2ecf20Sopenharmony_ci 52198c2ecf20Sopenharmony_ci rxbd = &rx_ring[i][0]; 52208c2ecf20Sopenharmony_ci for (j = 0; j < BNX2_MAX_RX_DESC_CNT; j++, rxbd++) { 52218c2ecf20Sopenharmony_ci rxbd->rx_bd_len = buf_size; 52228c2ecf20Sopenharmony_ci rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END; 52238c2ecf20Sopenharmony_ci } 52248c2ecf20Sopenharmony_ci if (i == (num_rings - 1)) 52258c2ecf20Sopenharmony_ci j = 0; 52268c2ecf20Sopenharmony_ci else 52278c2ecf20Sopenharmony_ci j = i + 1; 52288c2ecf20Sopenharmony_ci rxbd->rx_bd_haddr_hi = (u64) dma[j] >> 32; 52298c2ecf20Sopenharmony_ci rxbd->rx_bd_haddr_lo = (u64) dma[j] & 0xffffffff; 52308c2ecf20Sopenharmony_ci } 52318c2ecf20Sopenharmony_ci} 52328c2ecf20Sopenharmony_ci 52338c2ecf20Sopenharmony_cistatic void 52348c2ecf20Sopenharmony_cibnx2_init_rx_ring(struct bnx2 *bp, int ring_num) 52358c2ecf20Sopenharmony_ci{ 52368c2ecf20Sopenharmony_ci int i; 52378c2ecf20Sopenharmony_ci u16 prod, ring_prod; 52388c2ecf20Sopenharmony_ci u32 cid, rx_cid_addr, val; 52398c2ecf20Sopenharmony_ci struct bnx2_napi *bnapi = &bp->bnx2_napi[ring_num]; 52408c2ecf20Sopenharmony_ci struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring; 52418c2ecf20Sopenharmony_ci 52428c2ecf20Sopenharmony_ci if (ring_num == 0) 52438c2ecf20Sopenharmony_ci cid = RX_CID; 52448c2ecf20Sopenharmony_ci else 52458c2ecf20Sopenharmony_ci cid = RX_RSS_CID + ring_num - 1; 52468c2ecf20Sopenharmony_ci 52478c2ecf20Sopenharmony_ci rx_cid_addr = GET_CID_ADDR(cid); 52488c2ecf20Sopenharmony_ci 52498c2ecf20Sopenharmony_ci bnx2_init_rxbd_rings(rxr->rx_desc_ring, rxr->rx_desc_mapping, 52508c2ecf20Sopenharmony_ci bp->rx_buf_use_size, bp->rx_max_ring); 52518c2ecf20Sopenharmony_ci 52528c2ecf20Sopenharmony_ci bnx2_init_rx_context(bp, cid); 52538c2ecf20Sopenharmony_ci 52548c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5709) { 52558c2ecf20Sopenharmony_ci val = BNX2_RD(bp, BNX2_MQ_MAP_L2_5); 52568c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_MQ_MAP_L2_5, val | BNX2_MQ_MAP_L2_5_ARM); 52578c2ecf20Sopenharmony_ci } 52588c2ecf20Sopenharmony_ci 52598c2ecf20Sopenharmony_ci bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, 0); 52608c2ecf20Sopenharmony_ci if (bp->rx_pg_ring_size) { 52618c2ecf20Sopenharmony_ci bnx2_init_rxbd_rings(rxr->rx_pg_desc_ring, 52628c2ecf20Sopenharmony_ci rxr->rx_pg_desc_mapping, 52638c2ecf20Sopenharmony_ci PAGE_SIZE, bp->rx_max_pg_ring); 52648c2ecf20Sopenharmony_ci val = (bp->rx_buf_use_size << 16) | PAGE_SIZE; 52658c2ecf20Sopenharmony_ci bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_PG_BUF_SIZE, val); 52668c2ecf20Sopenharmony_ci bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_RBDC_KEY, 52678c2ecf20Sopenharmony_ci BNX2_L2CTX_RBDC_JUMBO_KEY - ring_num); 52688c2ecf20Sopenharmony_ci 52698c2ecf20Sopenharmony_ci val = (u64) rxr->rx_pg_desc_mapping[0] >> 32; 52708c2ecf20Sopenharmony_ci bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_HI, val); 52718c2ecf20Sopenharmony_ci 52728c2ecf20Sopenharmony_ci val = (u64) rxr->rx_pg_desc_mapping[0] & 0xffffffff; 52738c2ecf20Sopenharmony_ci bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_PG_BDHADDR_LO, val); 52748c2ecf20Sopenharmony_ci 52758c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5709) 52768c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_MQ_MAP_L2_3, BNX2_MQ_MAP_L2_3_DEFAULT); 52778c2ecf20Sopenharmony_ci } 52788c2ecf20Sopenharmony_ci 52798c2ecf20Sopenharmony_ci val = (u64) rxr->rx_desc_mapping[0] >> 32; 52808c2ecf20Sopenharmony_ci bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_HI, val); 52818c2ecf20Sopenharmony_ci 52828c2ecf20Sopenharmony_ci val = (u64) rxr->rx_desc_mapping[0] & 0xffffffff; 52838c2ecf20Sopenharmony_ci bnx2_ctx_wr(bp, rx_cid_addr, BNX2_L2CTX_NX_BDHADDR_LO, val); 52848c2ecf20Sopenharmony_ci 52858c2ecf20Sopenharmony_ci ring_prod = prod = rxr->rx_pg_prod; 52868c2ecf20Sopenharmony_ci for (i = 0; i < bp->rx_pg_ring_size; i++) { 52878c2ecf20Sopenharmony_ci if (bnx2_alloc_rx_page(bp, rxr, ring_prod, GFP_KERNEL) < 0) { 52888c2ecf20Sopenharmony_ci netdev_warn(bp->dev, "init'ed rx page ring %d with %d/%d pages only\n", 52898c2ecf20Sopenharmony_ci ring_num, i, bp->rx_pg_ring_size); 52908c2ecf20Sopenharmony_ci break; 52918c2ecf20Sopenharmony_ci } 52928c2ecf20Sopenharmony_ci prod = BNX2_NEXT_RX_BD(prod); 52938c2ecf20Sopenharmony_ci ring_prod = BNX2_RX_PG_RING_IDX(prod); 52948c2ecf20Sopenharmony_ci } 52958c2ecf20Sopenharmony_ci rxr->rx_pg_prod = prod; 52968c2ecf20Sopenharmony_ci 52978c2ecf20Sopenharmony_ci ring_prod = prod = rxr->rx_prod; 52988c2ecf20Sopenharmony_ci for (i = 0; i < bp->rx_ring_size; i++) { 52998c2ecf20Sopenharmony_ci if (bnx2_alloc_rx_data(bp, rxr, ring_prod, GFP_KERNEL) < 0) { 53008c2ecf20Sopenharmony_ci netdev_warn(bp->dev, "init'ed rx ring %d with %d/%d skbs only\n", 53018c2ecf20Sopenharmony_ci ring_num, i, bp->rx_ring_size); 53028c2ecf20Sopenharmony_ci break; 53038c2ecf20Sopenharmony_ci } 53048c2ecf20Sopenharmony_ci prod = BNX2_NEXT_RX_BD(prod); 53058c2ecf20Sopenharmony_ci ring_prod = BNX2_RX_RING_IDX(prod); 53068c2ecf20Sopenharmony_ci } 53078c2ecf20Sopenharmony_ci rxr->rx_prod = prod; 53088c2ecf20Sopenharmony_ci 53098c2ecf20Sopenharmony_ci rxr->rx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_BDIDX; 53108c2ecf20Sopenharmony_ci rxr->rx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_BSEQ; 53118c2ecf20Sopenharmony_ci rxr->rx_pg_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_HOST_PG_BDIDX; 53128c2ecf20Sopenharmony_ci 53138c2ecf20Sopenharmony_ci BNX2_WR16(bp, rxr->rx_pg_bidx_addr, rxr->rx_pg_prod); 53148c2ecf20Sopenharmony_ci BNX2_WR16(bp, rxr->rx_bidx_addr, prod); 53158c2ecf20Sopenharmony_ci 53168c2ecf20Sopenharmony_ci BNX2_WR(bp, rxr->rx_bseq_addr, rxr->rx_prod_bseq); 53178c2ecf20Sopenharmony_ci} 53188c2ecf20Sopenharmony_ci 53198c2ecf20Sopenharmony_cistatic void 53208c2ecf20Sopenharmony_cibnx2_init_all_rings(struct bnx2 *bp) 53218c2ecf20Sopenharmony_ci{ 53228c2ecf20Sopenharmony_ci int i; 53238c2ecf20Sopenharmony_ci u32 val; 53248c2ecf20Sopenharmony_ci 53258c2ecf20Sopenharmony_ci bnx2_clear_ring_states(bp); 53268c2ecf20Sopenharmony_ci 53278c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_TSCH_TSS_CFG, 0); 53288c2ecf20Sopenharmony_ci for (i = 0; i < bp->num_tx_rings; i++) 53298c2ecf20Sopenharmony_ci bnx2_init_tx_ring(bp, i); 53308c2ecf20Sopenharmony_ci 53318c2ecf20Sopenharmony_ci if (bp->num_tx_rings > 1) 53328c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_TSCH_TSS_CFG, ((bp->num_tx_rings - 1) << 24) | 53338c2ecf20Sopenharmony_ci (TX_TSS_CID << 7)); 53348c2ecf20Sopenharmony_ci 53358c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_RLUP_RSS_CONFIG, 0); 53368c2ecf20Sopenharmony_ci bnx2_reg_wr_ind(bp, BNX2_RXP_SCRATCH_RSS_TBL_SZ, 0); 53378c2ecf20Sopenharmony_ci 53388c2ecf20Sopenharmony_ci for (i = 0; i < bp->num_rx_rings; i++) 53398c2ecf20Sopenharmony_ci bnx2_init_rx_ring(bp, i); 53408c2ecf20Sopenharmony_ci 53418c2ecf20Sopenharmony_ci if (bp->num_rx_rings > 1) { 53428c2ecf20Sopenharmony_ci u32 tbl_32 = 0; 53438c2ecf20Sopenharmony_ci 53448c2ecf20Sopenharmony_ci for (i = 0; i < BNX2_RXP_SCRATCH_RSS_TBL_MAX_ENTRIES; i++) { 53458c2ecf20Sopenharmony_ci int shift = (i % 8) << 2; 53468c2ecf20Sopenharmony_ci 53478c2ecf20Sopenharmony_ci tbl_32 |= (i % (bp->num_rx_rings - 1)) << shift; 53488c2ecf20Sopenharmony_ci if ((i % 8) == 7) { 53498c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_RLUP_RSS_DATA, tbl_32); 53508c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_RLUP_RSS_COMMAND, (i >> 3) | 53518c2ecf20Sopenharmony_ci BNX2_RLUP_RSS_COMMAND_RSS_WRITE_MASK | 53528c2ecf20Sopenharmony_ci BNX2_RLUP_RSS_COMMAND_WRITE | 53538c2ecf20Sopenharmony_ci BNX2_RLUP_RSS_COMMAND_HASH_MASK); 53548c2ecf20Sopenharmony_ci tbl_32 = 0; 53558c2ecf20Sopenharmony_ci } 53568c2ecf20Sopenharmony_ci } 53578c2ecf20Sopenharmony_ci 53588c2ecf20Sopenharmony_ci val = BNX2_RLUP_RSS_CONFIG_IPV4_RSS_TYPE_ALL_XI | 53598c2ecf20Sopenharmony_ci BNX2_RLUP_RSS_CONFIG_IPV6_RSS_TYPE_ALL_XI; 53608c2ecf20Sopenharmony_ci 53618c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_RLUP_RSS_CONFIG, val); 53628c2ecf20Sopenharmony_ci 53638c2ecf20Sopenharmony_ci } 53648c2ecf20Sopenharmony_ci} 53658c2ecf20Sopenharmony_ci 53668c2ecf20Sopenharmony_cistatic u32 bnx2_find_max_ring(u32 ring_size, u32 max_size) 53678c2ecf20Sopenharmony_ci{ 53688c2ecf20Sopenharmony_ci u32 max, num_rings = 1; 53698c2ecf20Sopenharmony_ci 53708c2ecf20Sopenharmony_ci while (ring_size > BNX2_MAX_RX_DESC_CNT) { 53718c2ecf20Sopenharmony_ci ring_size -= BNX2_MAX_RX_DESC_CNT; 53728c2ecf20Sopenharmony_ci num_rings++; 53738c2ecf20Sopenharmony_ci } 53748c2ecf20Sopenharmony_ci /* round to next power of 2 */ 53758c2ecf20Sopenharmony_ci max = max_size; 53768c2ecf20Sopenharmony_ci while ((max & num_rings) == 0) 53778c2ecf20Sopenharmony_ci max >>= 1; 53788c2ecf20Sopenharmony_ci 53798c2ecf20Sopenharmony_ci if (num_rings != max) 53808c2ecf20Sopenharmony_ci max <<= 1; 53818c2ecf20Sopenharmony_ci 53828c2ecf20Sopenharmony_ci return max; 53838c2ecf20Sopenharmony_ci} 53848c2ecf20Sopenharmony_ci 53858c2ecf20Sopenharmony_cistatic void 53868c2ecf20Sopenharmony_cibnx2_set_rx_ring_size(struct bnx2 *bp, u32 size) 53878c2ecf20Sopenharmony_ci{ 53888c2ecf20Sopenharmony_ci u32 rx_size, rx_space, jumbo_size; 53898c2ecf20Sopenharmony_ci 53908c2ecf20Sopenharmony_ci /* 8 for CRC and VLAN */ 53918c2ecf20Sopenharmony_ci rx_size = bp->dev->mtu + ETH_HLEN + BNX2_RX_OFFSET + 8; 53928c2ecf20Sopenharmony_ci 53938c2ecf20Sopenharmony_ci rx_space = SKB_DATA_ALIGN(rx_size + BNX2_RX_ALIGN) + NET_SKB_PAD + 53948c2ecf20Sopenharmony_ci SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); 53958c2ecf20Sopenharmony_ci 53968c2ecf20Sopenharmony_ci bp->rx_copy_thresh = BNX2_RX_COPY_THRESH; 53978c2ecf20Sopenharmony_ci bp->rx_pg_ring_size = 0; 53988c2ecf20Sopenharmony_ci bp->rx_max_pg_ring = 0; 53998c2ecf20Sopenharmony_ci bp->rx_max_pg_ring_idx = 0; 54008c2ecf20Sopenharmony_ci if ((rx_space > PAGE_SIZE) && !(bp->flags & BNX2_FLAG_JUMBO_BROKEN)) { 54018c2ecf20Sopenharmony_ci int pages = PAGE_ALIGN(bp->dev->mtu - 40) >> PAGE_SHIFT; 54028c2ecf20Sopenharmony_ci 54038c2ecf20Sopenharmony_ci jumbo_size = size * pages; 54048c2ecf20Sopenharmony_ci if (jumbo_size > BNX2_MAX_TOTAL_RX_PG_DESC_CNT) 54058c2ecf20Sopenharmony_ci jumbo_size = BNX2_MAX_TOTAL_RX_PG_DESC_CNT; 54068c2ecf20Sopenharmony_ci 54078c2ecf20Sopenharmony_ci bp->rx_pg_ring_size = jumbo_size; 54088c2ecf20Sopenharmony_ci bp->rx_max_pg_ring = bnx2_find_max_ring(jumbo_size, 54098c2ecf20Sopenharmony_ci BNX2_MAX_RX_PG_RINGS); 54108c2ecf20Sopenharmony_ci bp->rx_max_pg_ring_idx = 54118c2ecf20Sopenharmony_ci (bp->rx_max_pg_ring * BNX2_RX_DESC_CNT) - 1; 54128c2ecf20Sopenharmony_ci rx_size = BNX2_RX_COPY_THRESH + BNX2_RX_OFFSET; 54138c2ecf20Sopenharmony_ci bp->rx_copy_thresh = 0; 54148c2ecf20Sopenharmony_ci } 54158c2ecf20Sopenharmony_ci 54168c2ecf20Sopenharmony_ci bp->rx_buf_use_size = rx_size; 54178c2ecf20Sopenharmony_ci /* hw alignment + build_skb() overhead*/ 54188c2ecf20Sopenharmony_ci bp->rx_buf_size = SKB_DATA_ALIGN(bp->rx_buf_use_size + BNX2_RX_ALIGN) + 54198c2ecf20Sopenharmony_ci NET_SKB_PAD + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); 54208c2ecf20Sopenharmony_ci bp->rx_jumbo_thresh = rx_size - BNX2_RX_OFFSET; 54218c2ecf20Sopenharmony_ci bp->rx_ring_size = size; 54228c2ecf20Sopenharmony_ci bp->rx_max_ring = bnx2_find_max_ring(size, BNX2_MAX_RX_RINGS); 54238c2ecf20Sopenharmony_ci bp->rx_max_ring_idx = (bp->rx_max_ring * BNX2_RX_DESC_CNT) - 1; 54248c2ecf20Sopenharmony_ci} 54258c2ecf20Sopenharmony_ci 54268c2ecf20Sopenharmony_cistatic void 54278c2ecf20Sopenharmony_cibnx2_free_tx_skbs(struct bnx2 *bp) 54288c2ecf20Sopenharmony_ci{ 54298c2ecf20Sopenharmony_ci int i; 54308c2ecf20Sopenharmony_ci 54318c2ecf20Sopenharmony_ci for (i = 0; i < bp->num_tx_rings; i++) { 54328c2ecf20Sopenharmony_ci struct bnx2_napi *bnapi = &bp->bnx2_napi[i]; 54338c2ecf20Sopenharmony_ci struct bnx2_tx_ring_info *txr = &bnapi->tx_ring; 54348c2ecf20Sopenharmony_ci int j; 54358c2ecf20Sopenharmony_ci 54368c2ecf20Sopenharmony_ci if (!txr->tx_buf_ring) 54378c2ecf20Sopenharmony_ci continue; 54388c2ecf20Sopenharmony_ci 54398c2ecf20Sopenharmony_ci for (j = 0; j < BNX2_TX_DESC_CNT; ) { 54408c2ecf20Sopenharmony_ci struct bnx2_sw_tx_bd *tx_buf = &txr->tx_buf_ring[j]; 54418c2ecf20Sopenharmony_ci struct sk_buff *skb = tx_buf->skb; 54428c2ecf20Sopenharmony_ci int k, last; 54438c2ecf20Sopenharmony_ci 54448c2ecf20Sopenharmony_ci if (!skb) { 54458c2ecf20Sopenharmony_ci j = BNX2_NEXT_TX_BD(j); 54468c2ecf20Sopenharmony_ci continue; 54478c2ecf20Sopenharmony_ci } 54488c2ecf20Sopenharmony_ci 54498c2ecf20Sopenharmony_ci dma_unmap_single(&bp->pdev->dev, 54508c2ecf20Sopenharmony_ci dma_unmap_addr(tx_buf, mapping), 54518c2ecf20Sopenharmony_ci skb_headlen(skb), 54528c2ecf20Sopenharmony_ci PCI_DMA_TODEVICE); 54538c2ecf20Sopenharmony_ci 54548c2ecf20Sopenharmony_ci tx_buf->skb = NULL; 54558c2ecf20Sopenharmony_ci 54568c2ecf20Sopenharmony_ci last = tx_buf->nr_frags; 54578c2ecf20Sopenharmony_ci j = BNX2_NEXT_TX_BD(j); 54588c2ecf20Sopenharmony_ci for (k = 0; k < last; k++, j = BNX2_NEXT_TX_BD(j)) { 54598c2ecf20Sopenharmony_ci tx_buf = &txr->tx_buf_ring[BNX2_TX_RING_IDX(j)]; 54608c2ecf20Sopenharmony_ci dma_unmap_page(&bp->pdev->dev, 54618c2ecf20Sopenharmony_ci dma_unmap_addr(tx_buf, mapping), 54628c2ecf20Sopenharmony_ci skb_frag_size(&skb_shinfo(skb)->frags[k]), 54638c2ecf20Sopenharmony_ci PCI_DMA_TODEVICE); 54648c2ecf20Sopenharmony_ci } 54658c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 54668c2ecf20Sopenharmony_ci } 54678c2ecf20Sopenharmony_ci netdev_tx_reset_queue(netdev_get_tx_queue(bp->dev, i)); 54688c2ecf20Sopenharmony_ci } 54698c2ecf20Sopenharmony_ci} 54708c2ecf20Sopenharmony_ci 54718c2ecf20Sopenharmony_cistatic void 54728c2ecf20Sopenharmony_cibnx2_free_rx_skbs(struct bnx2 *bp) 54738c2ecf20Sopenharmony_ci{ 54748c2ecf20Sopenharmony_ci int i; 54758c2ecf20Sopenharmony_ci 54768c2ecf20Sopenharmony_ci for (i = 0; i < bp->num_rx_rings; i++) { 54778c2ecf20Sopenharmony_ci struct bnx2_napi *bnapi = &bp->bnx2_napi[i]; 54788c2ecf20Sopenharmony_ci struct bnx2_rx_ring_info *rxr = &bnapi->rx_ring; 54798c2ecf20Sopenharmony_ci int j; 54808c2ecf20Sopenharmony_ci 54818c2ecf20Sopenharmony_ci if (!rxr->rx_buf_ring) 54828c2ecf20Sopenharmony_ci return; 54838c2ecf20Sopenharmony_ci 54848c2ecf20Sopenharmony_ci for (j = 0; j < bp->rx_max_ring_idx; j++) { 54858c2ecf20Sopenharmony_ci struct bnx2_sw_bd *rx_buf = &rxr->rx_buf_ring[j]; 54868c2ecf20Sopenharmony_ci u8 *data = rx_buf->data; 54878c2ecf20Sopenharmony_ci 54888c2ecf20Sopenharmony_ci if (!data) 54898c2ecf20Sopenharmony_ci continue; 54908c2ecf20Sopenharmony_ci 54918c2ecf20Sopenharmony_ci dma_unmap_single(&bp->pdev->dev, 54928c2ecf20Sopenharmony_ci dma_unmap_addr(rx_buf, mapping), 54938c2ecf20Sopenharmony_ci bp->rx_buf_use_size, 54948c2ecf20Sopenharmony_ci PCI_DMA_FROMDEVICE); 54958c2ecf20Sopenharmony_ci 54968c2ecf20Sopenharmony_ci rx_buf->data = NULL; 54978c2ecf20Sopenharmony_ci 54988c2ecf20Sopenharmony_ci kfree(data); 54998c2ecf20Sopenharmony_ci } 55008c2ecf20Sopenharmony_ci for (j = 0; j < bp->rx_max_pg_ring_idx; j++) 55018c2ecf20Sopenharmony_ci bnx2_free_rx_page(bp, rxr, j); 55028c2ecf20Sopenharmony_ci } 55038c2ecf20Sopenharmony_ci} 55048c2ecf20Sopenharmony_ci 55058c2ecf20Sopenharmony_cistatic void 55068c2ecf20Sopenharmony_cibnx2_free_skbs(struct bnx2 *bp) 55078c2ecf20Sopenharmony_ci{ 55088c2ecf20Sopenharmony_ci bnx2_free_tx_skbs(bp); 55098c2ecf20Sopenharmony_ci bnx2_free_rx_skbs(bp); 55108c2ecf20Sopenharmony_ci} 55118c2ecf20Sopenharmony_ci 55128c2ecf20Sopenharmony_cistatic int 55138c2ecf20Sopenharmony_cibnx2_reset_nic(struct bnx2 *bp, u32 reset_code) 55148c2ecf20Sopenharmony_ci{ 55158c2ecf20Sopenharmony_ci int rc; 55168c2ecf20Sopenharmony_ci 55178c2ecf20Sopenharmony_ci rc = bnx2_reset_chip(bp, reset_code); 55188c2ecf20Sopenharmony_ci bnx2_free_skbs(bp); 55198c2ecf20Sopenharmony_ci if (rc) 55208c2ecf20Sopenharmony_ci return rc; 55218c2ecf20Sopenharmony_ci 55228c2ecf20Sopenharmony_ci if ((rc = bnx2_init_chip(bp)) != 0) 55238c2ecf20Sopenharmony_ci return rc; 55248c2ecf20Sopenharmony_ci 55258c2ecf20Sopenharmony_ci bnx2_init_all_rings(bp); 55268c2ecf20Sopenharmony_ci return 0; 55278c2ecf20Sopenharmony_ci} 55288c2ecf20Sopenharmony_ci 55298c2ecf20Sopenharmony_cistatic int 55308c2ecf20Sopenharmony_cibnx2_init_nic(struct bnx2 *bp, int reset_phy) 55318c2ecf20Sopenharmony_ci{ 55328c2ecf20Sopenharmony_ci int rc; 55338c2ecf20Sopenharmony_ci 55348c2ecf20Sopenharmony_ci if ((rc = bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET)) != 0) 55358c2ecf20Sopenharmony_ci return rc; 55368c2ecf20Sopenharmony_ci 55378c2ecf20Sopenharmony_ci spin_lock_bh(&bp->phy_lock); 55388c2ecf20Sopenharmony_ci bnx2_init_phy(bp, reset_phy); 55398c2ecf20Sopenharmony_ci bnx2_set_link(bp); 55408c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) 55418c2ecf20Sopenharmony_ci bnx2_remote_phy_event(bp); 55428c2ecf20Sopenharmony_ci spin_unlock_bh(&bp->phy_lock); 55438c2ecf20Sopenharmony_ci return 0; 55448c2ecf20Sopenharmony_ci} 55458c2ecf20Sopenharmony_ci 55468c2ecf20Sopenharmony_cistatic int 55478c2ecf20Sopenharmony_cibnx2_shutdown_chip(struct bnx2 *bp) 55488c2ecf20Sopenharmony_ci{ 55498c2ecf20Sopenharmony_ci u32 reset_code; 55508c2ecf20Sopenharmony_ci 55518c2ecf20Sopenharmony_ci if (bp->flags & BNX2_FLAG_NO_WOL) 55528c2ecf20Sopenharmony_ci reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN; 55538c2ecf20Sopenharmony_ci else if (bp->wol) 55548c2ecf20Sopenharmony_ci reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL; 55558c2ecf20Sopenharmony_ci else 55568c2ecf20Sopenharmony_ci reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL; 55578c2ecf20Sopenharmony_ci 55588c2ecf20Sopenharmony_ci return bnx2_reset_chip(bp, reset_code); 55598c2ecf20Sopenharmony_ci} 55608c2ecf20Sopenharmony_ci 55618c2ecf20Sopenharmony_cistatic int 55628c2ecf20Sopenharmony_cibnx2_test_registers(struct bnx2 *bp) 55638c2ecf20Sopenharmony_ci{ 55648c2ecf20Sopenharmony_ci int ret; 55658c2ecf20Sopenharmony_ci int i, is_5709; 55668c2ecf20Sopenharmony_ci static const struct { 55678c2ecf20Sopenharmony_ci u16 offset; 55688c2ecf20Sopenharmony_ci u16 flags; 55698c2ecf20Sopenharmony_ci#define BNX2_FL_NOT_5709 1 55708c2ecf20Sopenharmony_ci u32 rw_mask; 55718c2ecf20Sopenharmony_ci u32 ro_mask; 55728c2ecf20Sopenharmony_ci } reg_tbl[] = { 55738c2ecf20Sopenharmony_ci { 0x006c, 0, 0x00000000, 0x0000003f }, 55748c2ecf20Sopenharmony_ci { 0x0090, 0, 0xffffffff, 0x00000000 }, 55758c2ecf20Sopenharmony_ci { 0x0094, 0, 0x00000000, 0x00000000 }, 55768c2ecf20Sopenharmony_ci 55778c2ecf20Sopenharmony_ci { 0x0404, BNX2_FL_NOT_5709, 0x00003f00, 0x00000000 }, 55788c2ecf20Sopenharmony_ci { 0x0418, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff }, 55798c2ecf20Sopenharmony_ci { 0x041c, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff }, 55808c2ecf20Sopenharmony_ci { 0x0420, BNX2_FL_NOT_5709, 0x00000000, 0x80ffffff }, 55818c2ecf20Sopenharmony_ci { 0x0424, BNX2_FL_NOT_5709, 0x00000000, 0x00000000 }, 55828c2ecf20Sopenharmony_ci { 0x0428, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 }, 55838c2ecf20Sopenharmony_ci { 0x0450, BNX2_FL_NOT_5709, 0x00000000, 0x0000ffff }, 55848c2ecf20Sopenharmony_ci { 0x0454, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff }, 55858c2ecf20Sopenharmony_ci { 0x0458, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff }, 55868c2ecf20Sopenharmony_ci 55878c2ecf20Sopenharmony_ci { 0x0808, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff }, 55888c2ecf20Sopenharmony_ci { 0x0854, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff }, 55898c2ecf20Sopenharmony_ci { 0x0868, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 }, 55908c2ecf20Sopenharmony_ci { 0x086c, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 }, 55918c2ecf20Sopenharmony_ci { 0x0870, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 }, 55928c2ecf20Sopenharmony_ci { 0x0874, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 }, 55938c2ecf20Sopenharmony_ci 55948c2ecf20Sopenharmony_ci { 0x0c00, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 }, 55958c2ecf20Sopenharmony_ci { 0x0c04, BNX2_FL_NOT_5709, 0x00000000, 0x03ff0001 }, 55968c2ecf20Sopenharmony_ci { 0x0c08, BNX2_FL_NOT_5709, 0x0f0ff073, 0x00000000 }, 55978c2ecf20Sopenharmony_ci 55988c2ecf20Sopenharmony_ci { 0x1000, 0, 0x00000000, 0x00000001 }, 55998c2ecf20Sopenharmony_ci { 0x1004, BNX2_FL_NOT_5709, 0x00000000, 0x000f0001 }, 56008c2ecf20Sopenharmony_ci 56018c2ecf20Sopenharmony_ci { 0x1408, 0, 0x01c00800, 0x00000000 }, 56028c2ecf20Sopenharmony_ci { 0x149c, 0, 0x8000ffff, 0x00000000 }, 56038c2ecf20Sopenharmony_ci { 0x14a8, 0, 0x00000000, 0x000001ff }, 56048c2ecf20Sopenharmony_ci { 0x14ac, 0, 0x0fffffff, 0x10000000 }, 56058c2ecf20Sopenharmony_ci { 0x14b0, 0, 0x00000002, 0x00000001 }, 56068c2ecf20Sopenharmony_ci { 0x14b8, 0, 0x00000000, 0x00000000 }, 56078c2ecf20Sopenharmony_ci { 0x14c0, 0, 0x00000000, 0x00000009 }, 56088c2ecf20Sopenharmony_ci { 0x14c4, 0, 0x00003fff, 0x00000000 }, 56098c2ecf20Sopenharmony_ci { 0x14cc, 0, 0x00000000, 0x00000001 }, 56108c2ecf20Sopenharmony_ci { 0x14d0, 0, 0xffffffff, 0x00000000 }, 56118c2ecf20Sopenharmony_ci 56128c2ecf20Sopenharmony_ci { 0x1800, 0, 0x00000000, 0x00000001 }, 56138c2ecf20Sopenharmony_ci { 0x1804, 0, 0x00000000, 0x00000003 }, 56148c2ecf20Sopenharmony_ci 56158c2ecf20Sopenharmony_ci { 0x2800, 0, 0x00000000, 0x00000001 }, 56168c2ecf20Sopenharmony_ci { 0x2804, 0, 0x00000000, 0x00003f01 }, 56178c2ecf20Sopenharmony_ci { 0x2808, 0, 0x0f3f3f03, 0x00000000 }, 56188c2ecf20Sopenharmony_ci { 0x2810, 0, 0xffff0000, 0x00000000 }, 56198c2ecf20Sopenharmony_ci { 0x2814, 0, 0xffff0000, 0x00000000 }, 56208c2ecf20Sopenharmony_ci { 0x2818, 0, 0xffff0000, 0x00000000 }, 56218c2ecf20Sopenharmony_ci { 0x281c, 0, 0xffff0000, 0x00000000 }, 56228c2ecf20Sopenharmony_ci { 0x2834, 0, 0xffffffff, 0x00000000 }, 56238c2ecf20Sopenharmony_ci { 0x2840, 0, 0x00000000, 0xffffffff }, 56248c2ecf20Sopenharmony_ci { 0x2844, 0, 0x00000000, 0xffffffff }, 56258c2ecf20Sopenharmony_ci { 0x2848, 0, 0xffffffff, 0x00000000 }, 56268c2ecf20Sopenharmony_ci { 0x284c, 0, 0xf800f800, 0x07ff07ff }, 56278c2ecf20Sopenharmony_ci 56288c2ecf20Sopenharmony_ci { 0x2c00, 0, 0x00000000, 0x00000011 }, 56298c2ecf20Sopenharmony_ci { 0x2c04, 0, 0x00000000, 0x00030007 }, 56308c2ecf20Sopenharmony_ci 56318c2ecf20Sopenharmony_ci { 0x3c00, 0, 0x00000000, 0x00000001 }, 56328c2ecf20Sopenharmony_ci { 0x3c04, 0, 0x00000000, 0x00070000 }, 56338c2ecf20Sopenharmony_ci { 0x3c08, 0, 0x00007f71, 0x07f00000 }, 56348c2ecf20Sopenharmony_ci { 0x3c0c, 0, 0x1f3ffffc, 0x00000000 }, 56358c2ecf20Sopenharmony_ci { 0x3c10, 0, 0xffffffff, 0x00000000 }, 56368c2ecf20Sopenharmony_ci { 0x3c14, 0, 0x00000000, 0xffffffff }, 56378c2ecf20Sopenharmony_ci { 0x3c18, 0, 0x00000000, 0xffffffff }, 56388c2ecf20Sopenharmony_ci { 0x3c1c, 0, 0xfffff000, 0x00000000 }, 56398c2ecf20Sopenharmony_ci { 0x3c20, 0, 0xffffff00, 0x00000000 }, 56408c2ecf20Sopenharmony_ci 56418c2ecf20Sopenharmony_ci { 0x5004, 0, 0x00000000, 0x0000007f }, 56428c2ecf20Sopenharmony_ci { 0x5008, 0, 0x0f0007ff, 0x00000000 }, 56438c2ecf20Sopenharmony_ci 56448c2ecf20Sopenharmony_ci { 0x5c00, 0, 0x00000000, 0x00000001 }, 56458c2ecf20Sopenharmony_ci { 0x5c04, 0, 0x00000000, 0x0003000f }, 56468c2ecf20Sopenharmony_ci { 0x5c08, 0, 0x00000003, 0x00000000 }, 56478c2ecf20Sopenharmony_ci { 0x5c0c, 0, 0x0000fff8, 0x00000000 }, 56488c2ecf20Sopenharmony_ci { 0x5c10, 0, 0x00000000, 0xffffffff }, 56498c2ecf20Sopenharmony_ci { 0x5c80, 0, 0x00000000, 0x0f7113f1 }, 56508c2ecf20Sopenharmony_ci { 0x5c84, 0, 0x00000000, 0x0000f333 }, 56518c2ecf20Sopenharmony_ci { 0x5c88, 0, 0x00000000, 0x00077373 }, 56528c2ecf20Sopenharmony_ci { 0x5c8c, 0, 0x00000000, 0x0007f737 }, 56538c2ecf20Sopenharmony_ci 56548c2ecf20Sopenharmony_ci { 0x6808, 0, 0x0000ff7f, 0x00000000 }, 56558c2ecf20Sopenharmony_ci { 0x680c, 0, 0xffffffff, 0x00000000 }, 56568c2ecf20Sopenharmony_ci { 0x6810, 0, 0xffffffff, 0x00000000 }, 56578c2ecf20Sopenharmony_ci { 0x6814, 0, 0xffffffff, 0x00000000 }, 56588c2ecf20Sopenharmony_ci { 0x6818, 0, 0xffffffff, 0x00000000 }, 56598c2ecf20Sopenharmony_ci { 0x681c, 0, 0xffffffff, 0x00000000 }, 56608c2ecf20Sopenharmony_ci { 0x6820, 0, 0x00ff00ff, 0x00000000 }, 56618c2ecf20Sopenharmony_ci { 0x6824, 0, 0x00ff00ff, 0x00000000 }, 56628c2ecf20Sopenharmony_ci { 0x6828, 0, 0x00ff00ff, 0x00000000 }, 56638c2ecf20Sopenharmony_ci { 0x682c, 0, 0x03ff03ff, 0x00000000 }, 56648c2ecf20Sopenharmony_ci { 0x6830, 0, 0x03ff03ff, 0x00000000 }, 56658c2ecf20Sopenharmony_ci { 0x6834, 0, 0x03ff03ff, 0x00000000 }, 56668c2ecf20Sopenharmony_ci { 0x6838, 0, 0x03ff03ff, 0x00000000 }, 56678c2ecf20Sopenharmony_ci { 0x683c, 0, 0x0000ffff, 0x00000000 }, 56688c2ecf20Sopenharmony_ci { 0x6840, 0, 0x00000ff0, 0x00000000 }, 56698c2ecf20Sopenharmony_ci { 0x6844, 0, 0x00ffff00, 0x00000000 }, 56708c2ecf20Sopenharmony_ci { 0x684c, 0, 0xffffffff, 0x00000000 }, 56718c2ecf20Sopenharmony_ci { 0x6850, 0, 0x7f7f7f7f, 0x00000000 }, 56728c2ecf20Sopenharmony_ci { 0x6854, 0, 0x7f7f7f7f, 0x00000000 }, 56738c2ecf20Sopenharmony_ci { 0x6858, 0, 0x7f7f7f7f, 0x00000000 }, 56748c2ecf20Sopenharmony_ci { 0x685c, 0, 0x7f7f7f7f, 0x00000000 }, 56758c2ecf20Sopenharmony_ci { 0x6908, 0, 0x00000000, 0x0001ff0f }, 56768c2ecf20Sopenharmony_ci { 0x690c, 0, 0x00000000, 0x0ffe00f0 }, 56778c2ecf20Sopenharmony_ci 56788c2ecf20Sopenharmony_ci { 0xffff, 0, 0x00000000, 0x00000000 }, 56798c2ecf20Sopenharmony_ci }; 56808c2ecf20Sopenharmony_ci 56818c2ecf20Sopenharmony_ci ret = 0; 56828c2ecf20Sopenharmony_ci is_5709 = 0; 56838c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5709) 56848c2ecf20Sopenharmony_ci is_5709 = 1; 56858c2ecf20Sopenharmony_ci 56868c2ecf20Sopenharmony_ci for (i = 0; reg_tbl[i].offset != 0xffff; i++) { 56878c2ecf20Sopenharmony_ci u32 offset, rw_mask, ro_mask, save_val, val; 56888c2ecf20Sopenharmony_ci u16 flags = reg_tbl[i].flags; 56898c2ecf20Sopenharmony_ci 56908c2ecf20Sopenharmony_ci if (is_5709 && (flags & BNX2_FL_NOT_5709)) 56918c2ecf20Sopenharmony_ci continue; 56928c2ecf20Sopenharmony_ci 56938c2ecf20Sopenharmony_ci offset = (u32) reg_tbl[i].offset; 56948c2ecf20Sopenharmony_ci rw_mask = reg_tbl[i].rw_mask; 56958c2ecf20Sopenharmony_ci ro_mask = reg_tbl[i].ro_mask; 56968c2ecf20Sopenharmony_ci 56978c2ecf20Sopenharmony_ci save_val = readl(bp->regview + offset); 56988c2ecf20Sopenharmony_ci 56998c2ecf20Sopenharmony_ci writel(0, bp->regview + offset); 57008c2ecf20Sopenharmony_ci 57018c2ecf20Sopenharmony_ci val = readl(bp->regview + offset); 57028c2ecf20Sopenharmony_ci if ((val & rw_mask) != 0) { 57038c2ecf20Sopenharmony_ci goto reg_test_err; 57048c2ecf20Sopenharmony_ci } 57058c2ecf20Sopenharmony_ci 57068c2ecf20Sopenharmony_ci if ((val & ro_mask) != (save_val & ro_mask)) { 57078c2ecf20Sopenharmony_ci goto reg_test_err; 57088c2ecf20Sopenharmony_ci } 57098c2ecf20Sopenharmony_ci 57108c2ecf20Sopenharmony_ci writel(0xffffffff, bp->regview + offset); 57118c2ecf20Sopenharmony_ci 57128c2ecf20Sopenharmony_ci val = readl(bp->regview + offset); 57138c2ecf20Sopenharmony_ci if ((val & rw_mask) != rw_mask) { 57148c2ecf20Sopenharmony_ci goto reg_test_err; 57158c2ecf20Sopenharmony_ci } 57168c2ecf20Sopenharmony_ci 57178c2ecf20Sopenharmony_ci if ((val & ro_mask) != (save_val & ro_mask)) { 57188c2ecf20Sopenharmony_ci goto reg_test_err; 57198c2ecf20Sopenharmony_ci } 57208c2ecf20Sopenharmony_ci 57218c2ecf20Sopenharmony_ci writel(save_val, bp->regview + offset); 57228c2ecf20Sopenharmony_ci continue; 57238c2ecf20Sopenharmony_ci 57248c2ecf20Sopenharmony_cireg_test_err: 57258c2ecf20Sopenharmony_ci writel(save_val, bp->regview + offset); 57268c2ecf20Sopenharmony_ci ret = -ENODEV; 57278c2ecf20Sopenharmony_ci break; 57288c2ecf20Sopenharmony_ci } 57298c2ecf20Sopenharmony_ci return ret; 57308c2ecf20Sopenharmony_ci} 57318c2ecf20Sopenharmony_ci 57328c2ecf20Sopenharmony_cistatic int 57338c2ecf20Sopenharmony_cibnx2_do_mem_test(struct bnx2 *bp, u32 start, u32 size) 57348c2ecf20Sopenharmony_ci{ 57358c2ecf20Sopenharmony_ci static const u32 test_pattern[] = { 0x00000000, 0xffffffff, 0x55555555, 57368c2ecf20Sopenharmony_ci 0xaaaaaaaa , 0xaa55aa55, 0x55aa55aa }; 57378c2ecf20Sopenharmony_ci int i; 57388c2ecf20Sopenharmony_ci 57398c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(test_pattern) / 4; i++) { 57408c2ecf20Sopenharmony_ci u32 offset; 57418c2ecf20Sopenharmony_ci 57428c2ecf20Sopenharmony_ci for (offset = 0; offset < size; offset += 4) { 57438c2ecf20Sopenharmony_ci 57448c2ecf20Sopenharmony_ci bnx2_reg_wr_ind(bp, start + offset, test_pattern[i]); 57458c2ecf20Sopenharmony_ci 57468c2ecf20Sopenharmony_ci if (bnx2_reg_rd_ind(bp, start + offset) != 57478c2ecf20Sopenharmony_ci test_pattern[i]) { 57488c2ecf20Sopenharmony_ci return -ENODEV; 57498c2ecf20Sopenharmony_ci } 57508c2ecf20Sopenharmony_ci } 57518c2ecf20Sopenharmony_ci } 57528c2ecf20Sopenharmony_ci return 0; 57538c2ecf20Sopenharmony_ci} 57548c2ecf20Sopenharmony_ci 57558c2ecf20Sopenharmony_cistatic int 57568c2ecf20Sopenharmony_cibnx2_test_memory(struct bnx2 *bp) 57578c2ecf20Sopenharmony_ci{ 57588c2ecf20Sopenharmony_ci int ret = 0; 57598c2ecf20Sopenharmony_ci int i; 57608c2ecf20Sopenharmony_ci static struct mem_entry { 57618c2ecf20Sopenharmony_ci u32 offset; 57628c2ecf20Sopenharmony_ci u32 len; 57638c2ecf20Sopenharmony_ci } mem_tbl_5706[] = { 57648c2ecf20Sopenharmony_ci { 0x60000, 0x4000 }, 57658c2ecf20Sopenharmony_ci { 0xa0000, 0x3000 }, 57668c2ecf20Sopenharmony_ci { 0xe0000, 0x4000 }, 57678c2ecf20Sopenharmony_ci { 0x120000, 0x4000 }, 57688c2ecf20Sopenharmony_ci { 0x1a0000, 0x4000 }, 57698c2ecf20Sopenharmony_ci { 0x160000, 0x4000 }, 57708c2ecf20Sopenharmony_ci { 0xffffffff, 0 }, 57718c2ecf20Sopenharmony_ci }, 57728c2ecf20Sopenharmony_ci mem_tbl_5709[] = { 57738c2ecf20Sopenharmony_ci { 0x60000, 0x4000 }, 57748c2ecf20Sopenharmony_ci { 0xa0000, 0x3000 }, 57758c2ecf20Sopenharmony_ci { 0xe0000, 0x4000 }, 57768c2ecf20Sopenharmony_ci { 0x120000, 0x4000 }, 57778c2ecf20Sopenharmony_ci { 0x1a0000, 0x4000 }, 57788c2ecf20Sopenharmony_ci { 0xffffffff, 0 }, 57798c2ecf20Sopenharmony_ci }; 57808c2ecf20Sopenharmony_ci struct mem_entry *mem_tbl; 57818c2ecf20Sopenharmony_ci 57828c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5709) 57838c2ecf20Sopenharmony_ci mem_tbl = mem_tbl_5709; 57848c2ecf20Sopenharmony_ci else 57858c2ecf20Sopenharmony_ci mem_tbl = mem_tbl_5706; 57868c2ecf20Sopenharmony_ci 57878c2ecf20Sopenharmony_ci for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) { 57888c2ecf20Sopenharmony_ci if ((ret = bnx2_do_mem_test(bp, mem_tbl[i].offset, 57898c2ecf20Sopenharmony_ci mem_tbl[i].len)) != 0) { 57908c2ecf20Sopenharmony_ci return ret; 57918c2ecf20Sopenharmony_ci } 57928c2ecf20Sopenharmony_ci } 57938c2ecf20Sopenharmony_ci 57948c2ecf20Sopenharmony_ci return ret; 57958c2ecf20Sopenharmony_ci} 57968c2ecf20Sopenharmony_ci 57978c2ecf20Sopenharmony_ci#define BNX2_MAC_LOOPBACK 0 57988c2ecf20Sopenharmony_ci#define BNX2_PHY_LOOPBACK 1 57998c2ecf20Sopenharmony_ci 58008c2ecf20Sopenharmony_cistatic int 58018c2ecf20Sopenharmony_cibnx2_run_loopback(struct bnx2 *bp, int loopback_mode) 58028c2ecf20Sopenharmony_ci{ 58038c2ecf20Sopenharmony_ci unsigned int pkt_size, num_pkts, i; 58048c2ecf20Sopenharmony_ci struct sk_buff *skb; 58058c2ecf20Sopenharmony_ci u8 *data; 58068c2ecf20Sopenharmony_ci unsigned char *packet; 58078c2ecf20Sopenharmony_ci u16 rx_start_idx, rx_idx; 58088c2ecf20Sopenharmony_ci dma_addr_t map; 58098c2ecf20Sopenharmony_ci struct bnx2_tx_bd *txbd; 58108c2ecf20Sopenharmony_ci struct bnx2_sw_bd *rx_buf; 58118c2ecf20Sopenharmony_ci struct l2_fhdr *rx_hdr; 58128c2ecf20Sopenharmony_ci int ret = -ENODEV; 58138c2ecf20Sopenharmony_ci struct bnx2_napi *bnapi = &bp->bnx2_napi[0], *tx_napi; 58148c2ecf20Sopenharmony_ci struct bnx2_tx_ring_info *txr; 58158c2ecf20Sopenharmony_ci struct bnx2_rx_ring_info *rxr; 58168c2ecf20Sopenharmony_ci 58178c2ecf20Sopenharmony_ci tx_napi = bnapi; 58188c2ecf20Sopenharmony_ci 58198c2ecf20Sopenharmony_ci txr = &tx_napi->tx_ring; 58208c2ecf20Sopenharmony_ci rxr = &bnapi->rx_ring; 58218c2ecf20Sopenharmony_ci if (loopback_mode == BNX2_MAC_LOOPBACK) { 58228c2ecf20Sopenharmony_ci bp->loopback = MAC_LOOPBACK; 58238c2ecf20Sopenharmony_ci bnx2_set_mac_loopback(bp); 58248c2ecf20Sopenharmony_ci } 58258c2ecf20Sopenharmony_ci else if (loopback_mode == BNX2_PHY_LOOPBACK) { 58268c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) 58278c2ecf20Sopenharmony_ci return 0; 58288c2ecf20Sopenharmony_ci 58298c2ecf20Sopenharmony_ci bp->loopback = PHY_LOOPBACK; 58308c2ecf20Sopenharmony_ci bnx2_set_phy_loopback(bp); 58318c2ecf20Sopenharmony_ci } 58328c2ecf20Sopenharmony_ci else 58338c2ecf20Sopenharmony_ci return -EINVAL; 58348c2ecf20Sopenharmony_ci 58358c2ecf20Sopenharmony_ci pkt_size = min(bp->dev->mtu + ETH_HLEN, bp->rx_jumbo_thresh - 4); 58368c2ecf20Sopenharmony_ci skb = netdev_alloc_skb(bp->dev, pkt_size); 58378c2ecf20Sopenharmony_ci if (!skb) 58388c2ecf20Sopenharmony_ci return -ENOMEM; 58398c2ecf20Sopenharmony_ci packet = skb_put(skb, pkt_size); 58408c2ecf20Sopenharmony_ci memcpy(packet, bp->dev->dev_addr, ETH_ALEN); 58418c2ecf20Sopenharmony_ci memset(packet + ETH_ALEN, 0x0, 8); 58428c2ecf20Sopenharmony_ci for (i = 14; i < pkt_size; i++) 58438c2ecf20Sopenharmony_ci packet[i] = (unsigned char) (i & 0xff); 58448c2ecf20Sopenharmony_ci 58458c2ecf20Sopenharmony_ci map = dma_map_single(&bp->pdev->dev, skb->data, pkt_size, 58468c2ecf20Sopenharmony_ci PCI_DMA_TODEVICE); 58478c2ecf20Sopenharmony_ci if (dma_mapping_error(&bp->pdev->dev, map)) { 58488c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 58498c2ecf20Sopenharmony_ci return -EIO; 58508c2ecf20Sopenharmony_ci } 58518c2ecf20Sopenharmony_ci 58528c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_HC_COMMAND, 58538c2ecf20Sopenharmony_ci bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT); 58548c2ecf20Sopenharmony_ci 58558c2ecf20Sopenharmony_ci BNX2_RD(bp, BNX2_HC_COMMAND); 58568c2ecf20Sopenharmony_ci 58578c2ecf20Sopenharmony_ci udelay(5); 58588c2ecf20Sopenharmony_ci rx_start_idx = bnx2_get_hw_rx_cons(bnapi); 58598c2ecf20Sopenharmony_ci 58608c2ecf20Sopenharmony_ci num_pkts = 0; 58618c2ecf20Sopenharmony_ci 58628c2ecf20Sopenharmony_ci txbd = &txr->tx_desc_ring[BNX2_TX_RING_IDX(txr->tx_prod)]; 58638c2ecf20Sopenharmony_ci 58648c2ecf20Sopenharmony_ci txbd->tx_bd_haddr_hi = (u64) map >> 32; 58658c2ecf20Sopenharmony_ci txbd->tx_bd_haddr_lo = (u64) map & 0xffffffff; 58668c2ecf20Sopenharmony_ci txbd->tx_bd_mss_nbytes = pkt_size; 58678c2ecf20Sopenharmony_ci txbd->tx_bd_vlan_tag_flags = TX_BD_FLAGS_START | TX_BD_FLAGS_END; 58688c2ecf20Sopenharmony_ci 58698c2ecf20Sopenharmony_ci num_pkts++; 58708c2ecf20Sopenharmony_ci txr->tx_prod = BNX2_NEXT_TX_BD(txr->tx_prod); 58718c2ecf20Sopenharmony_ci txr->tx_prod_bseq += pkt_size; 58728c2ecf20Sopenharmony_ci 58738c2ecf20Sopenharmony_ci BNX2_WR16(bp, txr->tx_bidx_addr, txr->tx_prod); 58748c2ecf20Sopenharmony_ci BNX2_WR(bp, txr->tx_bseq_addr, txr->tx_prod_bseq); 58758c2ecf20Sopenharmony_ci 58768c2ecf20Sopenharmony_ci udelay(100); 58778c2ecf20Sopenharmony_ci 58788c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_HC_COMMAND, 58798c2ecf20Sopenharmony_ci bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT); 58808c2ecf20Sopenharmony_ci 58818c2ecf20Sopenharmony_ci BNX2_RD(bp, BNX2_HC_COMMAND); 58828c2ecf20Sopenharmony_ci 58838c2ecf20Sopenharmony_ci udelay(5); 58848c2ecf20Sopenharmony_ci 58858c2ecf20Sopenharmony_ci dma_unmap_single(&bp->pdev->dev, map, pkt_size, PCI_DMA_TODEVICE); 58868c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 58878c2ecf20Sopenharmony_ci 58888c2ecf20Sopenharmony_ci if (bnx2_get_hw_tx_cons(tx_napi) != txr->tx_prod) 58898c2ecf20Sopenharmony_ci goto loopback_test_done; 58908c2ecf20Sopenharmony_ci 58918c2ecf20Sopenharmony_ci rx_idx = bnx2_get_hw_rx_cons(bnapi); 58928c2ecf20Sopenharmony_ci if (rx_idx != rx_start_idx + num_pkts) { 58938c2ecf20Sopenharmony_ci goto loopback_test_done; 58948c2ecf20Sopenharmony_ci } 58958c2ecf20Sopenharmony_ci 58968c2ecf20Sopenharmony_ci rx_buf = &rxr->rx_buf_ring[rx_start_idx]; 58978c2ecf20Sopenharmony_ci data = rx_buf->data; 58988c2ecf20Sopenharmony_ci 58998c2ecf20Sopenharmony_ci rx_hdr = get_l2_fhdr(data); 59008c2ecf20Sopenharmony_ci data = (u8 *)rx_hdr + BNX2_RX_OFFSET; 59018c2ecf20Sopenharmony_ci 59028c2ecf20Sopenharmony_ci dma_sync_single_for_cpu(&bp->pdev->dev, 59038c2ecf20Sopenharmony_ci dma_unmap_addr(rx_buf, mapping), 59048c2ecf20Sopenharmony_ci bp->rx_buf_use_size, PCI_DMA_FROMDEVICE); 59058c2ecf20Sopenharmony_ci 59068c2ecf20Sopenharmony_ci if (rx_hdr->l2_fhdr_status & 59078c2ecf20Sopenharmony_ci (L2_FHDR_ERRORS_BAD_CRC | 59088c2ecf20Sopenharmony_ci L2_FHDR_ERRORS_PHY_DECODE | 59098c2ecf20Sopenharmony_ci L2_FHDR_ERRORS_ALIGNMENT | 59108c2ecf20Sopenharmony_ci L2_FHDR_ERRORS_TOO_SHORT | 59118c2ecf20Sopenharmony_ci L2_FHDR_ERRORS_GIANT_FRAME)) { 59128c2ecf20Sopenharmony_ci 59138c2ecf20Sopenharmony_ci goto loopback_test_done; 59148c2ecf20Sopenharmony_ci } 59158c2ecf20Sopenharmony_ci 59168c2ecf20Sopenharmony_ci if ((rx_hdr->l2_fhdr_pkt_len - 4) != pkt_size) { 59178c2ecf20Sopenharmony_ci goto loopback_test_done; 59188c2ecf20Sopenharmony_ci } 59198c2ecf20Sopenharmony_ci 59208c2ecf20Sopenharmony_ci for (i = 14; i < pkt_size; i++) { 59218c2ecf20Sopenharmony_ci if (*(data + i) != (unsigned char) (i & 0xff)) { 59228c2ecf20Sopenharmony_ci goto loopback_test_done; 59238c2ecf20Sopenharmony_ci } 59248c2ecf20Sopenharmony_ci } 59258c2ecf20Sopenharmony_ci 59268c2ecf20Sopenharmony_ci ret = 0; 59278c2ecf20Sopenharmony_ci 59288c2ecf20Sopenharmony_ciloopback_test_done: 59298c2ecf20Sopenharmony_ci bp->loopback = 0; 59308c2ecf20Sopenharmony_ci return ret; 59318c2ecf20Sopenharmony_ci} 59328c2ecf20Sopenharmony_ci 59338c2ecf20Sopenharmony_ci#define BNX2_MAC_LOOPBACK_FAILED 1 59348c2ecf20Sopenharmony_ci#define BNX2_PHY_LOOPBACK_FAILED 2 59358c2ecf20Sopenharmony_ci#define BNX2_LOOPBACK_FAILED (BNX2_MAC_LOOPBACK_FAILED | \ 59368c2ecf20Sopenharmony_ci BNX2_PHY_LOOPBACK_FAILED) 59378c2ecf20Sopenharmony_ci 59388c2ecf20Sopenharmony_cistatic int 59398c2ecf20Sopenharmony_cibnx2_test_loopback(struct bnx2 *bp) 59408c2ecf20Sopenharmony_ci{ 59418c2ecf20Sopenharmony_ci int rc = 0; 59428c2ecf20Sopenharmony_ci 59438c2ecf20Sopenharmony_ci if (!netif_running(bp->dev)) 59448c2ecf20Sopenharmony_ci return BNX2_LOOPBACK_FAILED; 59458c2ecf20Sopenharmony_ci 59468c2ecf20Sopenharmony_ci bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET); 59478c2ecf20Sopenharmony_ci spin_lock_bh(&bp->phy_lock); 59488c2ecf20Sopenharmony_ci bnx2_init_phy(bp, 1); 59498c2ecf20Sopenharmony_ci spin_unlock_bh(&bp->phy_lock); 59508c2ecf20Sopenharmony_ci if (bnx2_run_loopback(bp, BNX2_MAC_LOOPBACK)) 59518c2ecf20Sopenharmony_ci rc |= BNX2_MAC_LOOPBACK_FAILED; 59528c2ecf20Sopenharmony_ci if (bnx2_run_loopback(bp, BNX2_PHY_LOOPBACK)) 59538c2ecf20Sopenharmony_ci rc |= BNX2_PHY_LOOPBACK_FAILED; 59548c2ecf20Sopenharmony_ci return rc; 59558c2ecf20Sopenharmony_ci} 59568c2ecf20Sopenharmony_ci 59578c2ecf20Sopenharmony_ci#define NVRAM_SIZE 0x200 59588c2ecf20Sopenharmony_ci#define CRC32_RESIDUAL 0xdebb20e3 59598c2ecf20Sopenharmony_ci 59608c2ecf20Sopenharmony_cistatic int 59618c2ecf20Sopenharmony_cibnx2_test_nvram(struct bnx2 *bp) 59628c2ecf20Sopenharmony_ci{ 59638c2ecf20Sopenharmony_ci __be32 buf[NVRAM_SIZE / 4]; 59648c2ecf20Sopenharmony_ci u8 *data = (u8 *) buf; 59658c2ecf20Sopenharmony_ci int rc = 0; 59668c2ecf20Sopenharmony_ci u32 magic, csum; 59678c2ecf20Sopenharmony_ci 59688c2ecf20Sopenharmony_ci if ((rc = bnx2_nvram_read(bp, 0, data, 4)) != 0) 59698c2ecf20Sopenharmony_ci goto test_nvram_done; 59708c2ecf20Sopenharmony_ci 59718c2ecf20Sopenharmony_ci magic = be32_to_cpu(buf[0]); 59728c2ecf20Sopenharmony_ci if (magic != 0x669955aa) { 59738c2ecf20Sopenharmony_ci rc = -ENODEV; 59748c2ecf20Sopenharmony_ci goto test_nvram_done; 59758c2ecf20Sopenharmony_ci } 59768c2ecf20Sopenharmony_ci 59778c2ecf20Sopenharmony_ci if ((rc = bnx2_nvram_read(bp, 0x100, data, NVRAM_SIZE)) != 0) 59788c2ecf20Sopenharmony_ci goto test_nvram_done; 59798c2ecf20Sopenharmony_ci 59808c2ecf20Sopenharmony_ci csum = ether_crc_le(0x100, data); 59818c2ecf20Sopenharmony_ci if (csum != CRC32_RESIDUAL) { 59828c2ecf20Sopenharmony_ci rc = -ENODEV; 59838c2ecf20Sopenharmony_ci goto test_nvram_done; 59848c2ecf20Sopenharmony_ci } 59858c2ecf20Sopenharmony_ci 59868c2ecf20Sopenharmony_ci csum = ether_crc_le(0x100, data + 0x100); 59878c2ecf20Sopenharmony_ci if (csum != CRC32_RESIDUAL) { 59888c2ecf20Sopenharmony_ci rc = -ENODEV; 59898c2ecf20Sopenharmony_ci } 59908c2ecf20Sopenharmony_ci 59918c2ecf20Sopenharmony_citest_nvram_done: 59928c2ecf20Sopenharmony_ci return rc; 59938c2ecf20Sopenharmony_ci} 59948c2ecf20Sopenharmony_ci 59958c2ecf20Sopenharmony_cistatic int 59968c2ecf20Sopenharmony_cibnx2_test_link(struct bnx2 *bp) 59978c2ecf20Sopenharmony_ci{ 59988c2ecf20Sopenharmony_ci u32 bmsr; 59998c2ecf20Sopenharmony_ci 60008c2ecf20Sopenharmony_ci if (!netif_running(bp->dev)) 60018c2ecf20Sopenharmony_ci return -ENODEV; 60028c2ecf20Sopenharmony_ci 60038c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) { 60048c2ecf20Sopenharmony_ci if (bp->link_up) 60058c2ecf20Sopenharmony_ci return 0; 60068c2ecf20Sopenharmony_ci return -ENODEV; 60078c2ecf20Sopenharmony_ci } 60088c2ecf20Sopenharmony_ci spin_lock_bh(&bp->phy_lock); 60098c2ecf20Sopenharmony_ci bnx2_enable_bmsr1(bp); 60108c2ecf20Sopenharmony_ci bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr); 60118c2ecf20Sopenharmony_ci bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr); 60128c2ecf20Sopenharmony_ci bnx2_disable_bmsr1(bp); 60138c2ecf20Sopenharmony_ci spin_unlock_bh(&bp->phy_lock); 60148c2ecf20Sopenharmony_ci 60158c2ecf20Sopenharmony_ci if (bmsr & BMSR_LSTATUS) { 60168c2ecf20Sopenharmony_ci return 0; 60178c2ecf20Sopenharmony_ci } 60188c2ecf20Sopenharmony_ci return -ENODEV; 60198c2ecf20Sopenharmony_ci} 60208c2ecf20Sopenharmony_ci 60218c2ecf20Sopenharmony_cistatic int 60228c2ecf20Sopenharmony_cibnx2_test_intr(struct bnx2 *bp) 60238c2ecf20Sopenharmony_ci{ 60248c2ecf20Sopenharmony_ci int i; 60258c2ecf20Sopenharmony_ci u16 status_idx; 60268c2ecf20Sopenharmony_ci 60278c2ecf20Sopenharmony_ci if (!netif_running(bp->dev)) 60288c2ecf20Sopenharmony_ci return -ENODEV; 60298c2ecf20Sopenharmony_ci 60308c2ecf20Sopenharmony_ci status_idx = BNX2_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff; 60318c2ecf20Sopenharmony_ci 60328c2ecf20Sopenharmony_ci /* This register is not touched during run-time. */ 60338c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW); 60348c2ecf20Sopenharmony_ci BNX2_RD(bp, BNX2_HC_COMMAND); 60358c2ecf20Sopenharmony_ci 60368c2ecf20Sopenharmony_ci for (i = 0; i < 10; i++) { 60378c2ecf20Sopenharmony_ci if ((BNX2_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff) != 60388c2ecf20Sopenharmony_ci status_idx) { 60398c2ecf20Sopenharmony_ci 60408c2ecf20Sopenharmony_ci break; 60418c2ecf20Sopenharmony_ci } 60428c2ecf20Sopenharmony_ci 60438c2ecf20Sopenharmony_ci msleep_interruptible(10); 60448c2ecf20Sopenharmony_ci } 60458c2ecf20Sopenharmony_ci if (i < 10) 60468c2ecf20Sopenharmony_ci return 0; 60478c2ecf20Sopenharmony_ci 60488c2ecf20Sopenharmony_ci return -ENODEV; 60498c2ecf20Sopenharmony_ci} 60508c2ecf20Sopenharmony_ci 60518c2ecf20Sopenharmony_ci/* Determining link for parallel detection. */ 60528c2ecf20Sopenharmony_cistatic int 60538c2ecf20Sopenharmony_cibnx2_5706_serdes_has_link(struct bnx2 *bp) 60548c2ecf20Sopenharmony_ci{ 60558c2ecf20Sopenharmony_ci u32 mode_ctl, an_dbg, exp; 60568c2ecf20Sopenharmony_ci 60578c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_NO_PARALLEL) 60588c2ecf20Sopenharmony_ci return 0; 60598c2ecf20Sopenharmony_ci 60608c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_MODE_CTL); 60618c2ecf20Sopenharmony_ci bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &mode_ctl); 60628c2ecf20Sopenharmony_ci 60638c2ecf20Sopenharmony_ci if (!(mode_ctl & MISC_SHDW_MODE_CTL_SIG_DET)) 60648c2ecf20Sopenharmony_ci return 0; 60658c2ecf20Sopenharmony_ci 60668c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG); 60678c2ecf20Sopenharmony_ci bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg); 60688c2ecf20Sopenharmony_ci bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &an_dbg); 60698c2ecf20Sopenharmony_ci 60708c2ecf20Sopenharmony_ci if (an_dbg & (MISC_SHDW_AN_DBG_NOSYNC | MISC_SHDW_AN_DBG_RUDI_INVALID)) 60718c2ecf20Sopenharmony_ci return 0; 60728c2ecf20Sopenharmony_ci 60738c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS, MII_EXPAND_REG1); 60748c2ecf20Sopenharmony_ci bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &exp); 60758c2ecf20Sopenharmony_ci bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &exp); 60768c2ecf20Sopenharmony_ci 60778c2ecf20Sopenharmony_ci if (exp & MII_EXPAND_REG1_RUDI_C) /* receiving CONFIG */ 60788c2ecf20Sopenharmony_ci return 0; 60798c2ecf20Sopenharmony_ci 60808c2ecf20Sopenharmony_ci return 1; 60818c2ecf20Sopenharmony_ci} 60828c2ecf20Sopenharmony_ci 60838c2ecf20Sopenharmony_cistatic void 60848c2ecf20Sopenharmony_cibnx2_5706_serdes_timer(struct bnx2 *bp) 60858c2ecf20Sopenharmony_ci{ 60868c2ecf20Sopenharmony_ci int check_link = 1; 60878c2ecf20Sopenharmony_ci 60888c2ecf20Sopenharmony_ci spin_lock(&bp->phy_lock); 60898c2ecf20Sopenharmony_ci if (bp->serdes_an_pending) { 60908c2ecf20Sopenharmony_ci bp->serdes_an_pending--; 60918c2ecf20Sopenharmony_ci check_link = 0; 60928c2ecf20Sopenharmony_ci } else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) { 60938c2ecf20Sopenharmony_ci u32 bmcr; 60948c2ecf20Sopenharmony_ci 60958c2ecf20Sopenharmony_ci bp->current_interval = BNX2_TIMER_INTERVAL; 60968c2ecf20Sopenharmony_ci 60978c2ecf20Sopenharmony_ci bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); 60988c2ecf20Sopenharmony_ci 60998c2ecf20Sopenharmony_ci if (bmcr & BMCR_ANENABLE) { 61008c2ecf20Sopenharmony_ci if (bnx2_5706_serdes_has_link(bp)) { 61018c2ecf20Sopenharmony_ci bmcr &= ~BMCR_ANENABLE; 61028c2ecf20Sopenharmony_ci bmcr |= BMCR_SPEED1000 | BMCR_FULLDPLX; 61038c2ecf20Sopenharmony_ci bnx2_write_phy(bp, bp->mii_bmcr, bmcr); 61048c2ecf20Sopenharmony_ci bp->phy_flags |= BNX2_PHY_FLAG_PARALLEL_DETECT; 61058c2ecf20Sopenharmony_ci } 61068c2ecf20Sopenharmony_ci } 61078c2ecf20Sopenharmony_ci } 61088c2ecf20Sopenharmony_ci else if ((bp->link_up) && (bp->autoneg & AUTONEG_SPEED) && 61098c2ecf20Sopenharmony_ci (bp->phy_flags & BNX2_PHY_FLAG_PARALLEL_DETECT)) { 61108c2ecf20Sopenharmony_ci u32 phy2; 61118c2ecf20Sopenharmony_ci 61128c2ecf20Sopenharmony_ci bnx2_write_phy(bp, 0x17, 0x0f01); 61138c2ecf20Sopenharmony_ci bnx2_read_phy(bp, 0x15, &phy2); 61148c2ecf20Sopenharmony_ci if (phy2 & 0x20) { 61158c2ecf20Sopenharmony_ci u32 bmcr; 61168c2ecf20Sopenharmony_ci 61178c2ecf20Sopenharmony_ci bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); 61188c2ecf20Sopenharmony_ci bmcr |= BMCR_ANENABLE; 61198c2ecf20Sopenharmony_ci bnx2_write_phy(bp, bp->mii_bmcr, bmcr); 61208c2ecf20Sopenharmony_ci 61218c2ecf20Sopenharmony_ci bp->phy_flags &= ~BNX2_PHY_FLAG_PARALLEL_DETECT; 61228c2ecf20Sopenharmony_ci } 61238c2ecf20Sopenharmony_ci } else 61248c2ecf20Sopenharmony_ci bp->current_interval = BNX2_TIMER_INTERVAL; 61258c2ecf20Sopenharmony_ci 61268c2ecf20Sopenharmony_ci if (check_link) { 61278c2ecf20Sopenharmony_ci u32 val; 61288c2ecf20Sopenharmony_ci 61298c2ecf20Sopenharmony_ci bnx2_write_phy(bp, MII_BNX2_MISC_SHADOW, MISC_SHDW_AN_DBG); 61308c2ecf20Sopenharmony_ci bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val); 61318c2ecf20Sopenharmony_ci bnx2_read_phy(bp, MII_BNX2_MISC_SHADOW, &val); 61328c2ecf20Sopenharmony_ci 61338c2ecf20Sopenharmony_ci if (bp->link_up && (val & MISC_SHDW_AN_DBG_NOSYNC)) { 61348c2ecf20Sopenharmony_ci if (!(bp->phy_flags & BNX2_PHY_FLAG_FORCED_DOWN)) { 61358c2ecf20Sopenharmony_ci bnx2_5706s_force_link_dn(bp, 1); 61368c2ecf20Sopenharmony_ci bp->phy_flags |= BNX2_PHY_FLAG_FORCED_DOWN; 61378c2ecf20Sopenharmony_ci } else 61388c2ecf20Sopenharmony_ci bnx2_set_link(bp); 61398c2ecf20Sopenharmony_ci } else if (!bp->link_up && !(val & MISC_SHDW_AN_DBG_NOSYNC)) 61408c2ecf20Sopenharmony_ci bnx2_set_link(bp); 61418c2ecf20Sopenharmony_ci } 61428c2ecf20Sopenharmony_ci spin_unlock(&bp->phy_lock); 61438c2ecf20Sopenharmony_ci} 61448c2ecf20Sopenharmony_ci 61458c2ecf20Sopenharmony_cistatic void 61468c2ecf20Sopenharmony_cibnx2_5708_serdes_timer(struct bnx2 *bp) 61478c2ecf20Sopenharmony_ci{ 61488c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) 61498c2ecf20Sopenharmony_ci return; 61508c2ecf20Sopenharmony_ci 61518c2ecf20Sopenharmony_ci if ((bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) == 0) { 61528c2ecf20Sopenharmony_ci bp->serdes_an_pending = 0; 61538c2ecf20Sopenharmony_ci return; 61548c2ecf20Sopenharmony_ci } 61558c2ecf20Sopenharmony_ci 61568c2ecf20Sopenharmony_ci spin_lock(&bp->phy_lock); 61578c2ecf20Sopenharmony_ci if (bp->serdes_an_pending) 61588c2ecf20Sopenharmony_ci bp->serdes_an_pending--; 61598c2ecf20Sopenharmony_ci else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) { 61608c2ecf20Sopenharmony_ci u32 bmcr; 61618c2ecf20Sopenharmony_ci 61628c2ecf20Sopenharmony_ci bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); 61638c2ecf20Sopenharmony_ci if (bmcr & BMCR_ANENABLE) { 61648c2ecf20Sopenharmony_ci bnx2_enable_forced_2g5(bp); 61658c2ecf20Sopenharmony_ci bp->current_interval = BNX2_SERDES_FORCED_TIMEOUT; 61668c2ecf20Sopenharmony_ci } else { 61678c2ecf20Sopenharmony_ci bnx2_disable_forced_2g5(bp); 61688c2ecf20Sopenharmony_ci bp->serdes_an_pending = 2; 61698c2ecf20Sopenharmony_ci bp->current_interval = BNX2_TIMER_INTERVAL; 61708c2ecf20Sopenharmony_ci } 61718c2ecf20Sopenharmony_ci 61728c2ecf20Sopenharmony_ci } else 61738c2ecf20Sopenharmony_ci bp->current_interval = BNX2_TIMER_INTERVAL; 61748c2ecf20Sopenharmony_ci 61758c2ecf20Sopenharmony_ci spin_unlock(&bp->phy_lock); 61768c2ecf20Sopenharmony_ci} 61778c2ecf20Sopenharmony_ci 61788c2ecf20Sopenharmony_cistatic void 61798c2ecf20Sopenharmony_cibnx2_timer(struct timer_list *t) 61808c2ecf20Sopenharmony_ci{ 61818c2ecf20Sopenharmony_ci struct bnx2 *bp = from_timer(bp, t, timer); 61828c2ecf20Sopenharmony_ci 61838c2ecf20Sopenharmony_ci if (!netif_running(bp->dev)) 61848c2ecf20Sopenharmony_ci return; 61858c2ecf20Sopenharmony_ci 61868c2ecf20Sopenharmony_ci if (atomic_read(&bp->intr_sem) != 0) 61878c2ecf20Sopenharmony_ci goto bnx2_restart_timer; 61888c2ecf20Sopenharmony_ci 61898c2ecf20Sopenharmony_ci if ((bp->flags & (BNX2_FLAG_USING_MSI | BNX2_FLAG_ONE_SHOT_MSI)) == 61908c2ecf20Sopenharmony_ci BNX2_FLAG_USING_MSI) 61918c2ecf20Sopenharmony_ci bnx2_chk_missed_msi(bp); 61928c2ecf20Sopenharmony_ci 61938c2ecf20Sopenharmony_ci bnx2_send_heart_beat(bp); 61948c2ecf20Sopenharmony_ci 61958c2ecf20Sopenharmony_ci bp->stats_blk->stat_FwRxDrop = 61968c2ecf20Sopenharmony_ci bnx2_reg_rd_ind(bp, BNX2_FW_RX_DROP_COUNT); 61978c2ecf20Sopenharmony_ci 61988c2ecf20Sopenharmony_ci /* workaround occasional corrupted counters */ 61998c2ecf20Sopenharmony_ci if ((bp->flags & BNX2_FLAG_BROKEN_STATS) && bp->stats_ticks) 62008c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | 62018c2ecf20Sopenharmony_ci BNX2_HC_COMMAND_STATS_NOW); 62028c2ecf20Sopenharmony_ci 62038c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) { 62048c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5706) 62058c2ecf20Sopenharmony_ci bnx2_5706_serdes_timer(bp); 62068c2ecf20Sopenharmony_ci else 62078c2ecf20Sopenharmony_ci bnx2_5708_serdes_timer(bp); 62088c2ecf20Sopenharmony_ci } 62098c2ecf20Sopenharmony_ci 62108c2ecf20Sopenharmony_cibnx2_restart_timer: 62118c2ecf20Sopenharmony_ci mod_timer(&bp->timer, jiffies + bp->current_interval); 62128c2ecf20Sopenharmony_ci} 62138c2ecf20Sopenharmony_ci 62148c2ecf20Sopenharmony_cistatic int 62158c2ecf20Sopenharmony_cibnx2_request_irq(struct bnx2 *bp) 62168c2ecf20Sopenharmony_ci{ 62178c2ecf20Sopenharmony_ci unsigned long flags; 62188c2ecf20Sopenharmony_ci struct bnx2_irq *irq; 62198c2ecf20Sopenharmony_ci int rc = 0, i; 62208c2ecf20Sopenharmony_ci 62218c2ecf20Sopenharmony_ci if (bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX) 62228c2ecf20Sopenharmony_ci flags = 0; 62238c2ecf20Sopenharmony_ci else 62248c2ecf20Sopenharmony_ci flags = IRQF_SHARED; 62258c2ecf20Sopenharmony_ci 62268c2ecf20Sopenharmony_ci for (i = 0; i < bp->irq_nvecs; i++) { 62278c2ecf20Sopenharmony_ci irq = &bp->irq_tbl[i]; 62288c2ecf20Sopenharmony_ci rc = request_irq(irq->vector, irq->handler, flags, irq->name, 62298c2ecf20Sopenharmony_ci &bp->bnx2_napi[i]); 62308c2ecf20Sopenharmony_ci if (rc) 62318c2ecf20Sopenharmony_ci break; 62328c2ecf20Sopenharmony_ci irq->requested = 1; 62338c2ecf20Sopenharmony_ci } 62348c2ecf20Sopenharmony_ci return rc; 62358c2ecf20Sopenharmony_ci} 62368c2ecf20Sopenharmony_ci 62378c2ecf20Sopenharmony_cistatic void 62388c2ecf20Sopenharmony_ci__bnx2_free_irq(struct bnx2 *bp) 62398c2ecf20Sopenharmony_ci{ 62408c2ecf20Sopenharmony_ci struct bnx2_irq *irq; 62418c2ecf20Sopenharmony_ci int i; 62428c2ecf20Sopenharmony_ci 62438c2ecf20Sopenharmony_ci for (i = 0; i < bp->irq_nvecs; i++) { 62448c2ecf20Sopenharmony_ci irq = &bp->irq_tbl[i]; 62458c2ecf20Sopenharmony_ci if (irq->requested) 62468c2ecf20Sopenharmony_ci free_irq(irq->vector, &bp->bnx2_napi[i]); 62478c2ecf20Sopenharmony_ci irq->requested = 0; 62488c2ecf20Sopenharmony_ci } 62498c2ecf20Sopenharmony_ci} 62508c2ecf20Sopenharmony_ci 62518c2ecf20Sopenharmony_cistatic void 62528c2ecf20Sopenharmony_cibnx2_free_irq(struct bnx2 *bp) 62538c2ecf20Sopenharmony_ci{ 62548c2ecf20Sopenharmony_ci 62558c2ecf20Sopenharmony_ci __bnx2_free_irq(bp); 62568c2ecf20Sopenharmony_ci if (bp->flags & BNX2_FLAG_USING_MSI) 62578c2ecf20Sopenharmony_ci pci_disable_msi(bp->pdev); 62588c2ecf20Sopenharmony_ci else if (bp->flags & BNX2_FLAG_USING_MSIX) 62598c2ecf20Sopenharmony_ci pci_disable_msix(bp->pdev); 62608c2ecf20Sopenharmony_ci 62618c2ecf20Sopenharmony_ci bp->flags &= ~(BNX2_FLAG_USING_MSI_OR_MSIX | BNX2_FLAG_ONE_SHOT_MSI); 62628c2ecf20Sopenharmony_ci} 62638c2ecf20Sopenharmony_ci 62648c2ecf20Sopenharmony_cistatic void 62658c2ecf20Sopenharmony_cibnx2_enable_msix(struct bnx2 *bp, int msix_vecs) 62668c2ecf20Sopenharmony_ci{ 62678c2ecf20Sopenharmony_ci int i, total_vecs; 62688c2ecf20Sopenharmony_ci struct msix_entry msix_ent[BNX2_MAX_MSIX_VEC]; 62698c2ecf20Sopenharmony_ci struct net_device *dev = bp->dev; 62708c2ecf20Sopenharmony_ci const int len = sizeof(bp->irq_tbl[0].name); 62718c2ecf20Sopenharmony_ci 62728c2ecf20Sopenharmony_ci bnx2_setup_msix_tbl(bp); 62738c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_PCI_MSIX_CONTROL, BNX2_MAX_MSIX_HW_VEC - 1); 62748c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_PCI_MSIX_TBL_OFF_BIR, BNX2_PCI_GRC_WINDOW2_BASE); 62758c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_PCI_MSIX_PBA_OFF_BIT, BNX2_PCI_GRC_WINDOW3_BASE); 62768c2ecf20Sopenharmony_ci 62778c2ecf20Sopenharmony_ci /* Need to flush the previous three writes to ensure MSI-X 62788c2ecf20Sopenharmony_ci * is setup properly */ 62798c2ecf20Sopenharmony_ci BNX2_RD(bp, BNX2_PCI_MSIX_CONTROL); 62808c2ecf20Sopenharmony_ci 62818c2ecf20Sopenharmony_ci for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) { 62828c2ecf20Sopenharmony_ci msix_ent[i].entry = i; 62838c2ecf20Sopenharmony_ci msix_ent[i].vector = 0; 62848c2ecf20Sopenharmony_ci } 62858c2ecf20Sopenharmony_ci 62868c2ecf20Sopenharmony_ci total_vecs = msix_vecs; 62878c2ecf20Sopenharmony_ci#ifdef BCM_CNIC 62888c2ecf20Sopenharmony_ci total_vecs++; 62898c2ecf20Sopenharmony_ci#endif 62908c2ecf20Sopenharmony_ci total_vecs = pci_enable_msix_range(bp->pdev, msix_ent, 62918c2ecf20Sopenharmony_ci BNX2_MIN_MSIX_VEC, total_vecs); 62928c2ecf20Sopenharmony_ci if (total_vecs < 0) 62938c2ecf20Sopenharmony_ci return; 62948c2ecf20Sopenharmony_ci 62958c2ecf20Sopenharmony_ci msix_vecs = total_vecs; 62968c2ecf20Sopenharmony_ci#ifdef BCM_CNIC 62978c2ecf20Sopenharmony_ci msix_vecs--; 62988c2ecf20Sopenharmony_ci#endif 62998c2ecf20Sopenharmony_ci bp->irq_nvecs = msix_vecs; 63008c2ecf20Sopenharmony_ci bp->flags |= BNX2_FLAG_USING_MSIX | BNX2_FLAG_ONE_SHOT_MSI; 63018c2ecf20Sopenharmony_ci for (i = 0; i < total_vecs; i++) { 63028c2ecf20Sopenharmony_ci bp->irq_tbl[i].vector = msix_ent[i].vector; 63038c2ecf20Sopenharmony_ci snprintf(bp->irq_tbl[i].name, len, "%s-%d", dev->name, i); 63048c2ecf20Sopenharmony_ci bp->irq_tbl[i].handler = bnx2_msi_1shot; 63058c2ecf20Sopenharmony_ci } 63068c2ecf20Sopenharmony_ci} 63078c2ecf20Sopenharmony_ci 63088c2ecf20Sopenharmony_cistatic int 63098c2ecf20Sopenharmony_cibnx2_setup_int_mode(struct bnx2 *bp, int dis_msi) 63108c2ecf20Sopenharmony_ci{ 63118c2ecf20Sopenharmony_ci int cpus = netif_get_num_default_rss_queues(); 63128c2ecf20Sopenharmony_ci int msix_vecs; 63138c2ecf20Sopenharmony_ci 63148c2ecf20Sopenharmony_ci if (!bp->num_req_rx_rings) 63158c2ecf20Sopenharmony_ci msix_vecs = max(cpus + 1, bp->num_req_tx_rings); 63168c2ecf20Sopenharmony_ci else if (!bp->num_req_tx_rings) 63178c2ecf20Sopenharmony_ci msix_vecs = max(cpus, bp->num_req_rx_rings); 63188c2ecf20Sopenharmony_ci else 63198c2ecf20Sopenharmony_ci msix_vecs = max(bp->num_req_rx_rings, bp->num_req_tx_rings); 63208c2ecf20Sopenharmony_ci 63218c2ecf20Sopenharmony_ci msix_vecs = min(msix_vecs, RX_MAX_RINGS); 63228c2ecf20Sopenharmony_ci 63238c2ecf20Sopenharmony_ci bp->irq_tbl[0].handler = bnx2_interrupt; 63248c2ecf20Sopenharmony_ci strcpy(bp->irq_tbl[0].name, bp->dev->name); 63258c2ecf20Sopenharmony_ci bp->irq_nvecs = 1; 63268c2ecf20Sopenharmony_ci bp->irq_tbl[0].vector = bp->pdev->irq; 63278c2ecf20Sopenharmony_ci 63288c2ecf20Sopenharmony_ci if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !dis_msi) 63298c2ecf20Sopenharmony_ci bnx2_enable_msix(bp, msix_vecs); 63308c2ecf20Sopenharmony_ci 63318c2ecf20Sopenharmony_ci if ((bp->flags & BNX2_FLAG_MSI_CAP) && !dis_msi && 63328c2ecf20Sopenharmony_ci !(bp->flags & BNX2_FLAG_USING_MSIX)) { 63338c2ecf20Sopenharmony_ci if (pci_enable_msi(bp->pdev) == 0) { 63348c2ecf20Sopenharmony_ci bp->flags |= BNX2_FLAG_USING_MSI; 63358c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5709) { 63368c2ecf20Sopenharmony_ci bp->flags |= BNX2_FLAG_ONE_SHOT_MSI; 63378c2ecf20Sopenharmony_ci bp->irq_tbl[0].handler = bnx2_msi_1shot; 63388c2ecf20Sopenharmony_ci } else 63398c2ecf20Sopenharmony_ci bp->irq_tbl[0].handler = bnx2_msi; 63408c2ecf20Sopenharmony_ci 63418c2ecf20Sopenharmony_ci bp->irq_tbl[0].vector = bp->pdev->irq; 63428c2ecf20Sopenharmony_ci } 63438c2ecf20Sopenharmony_ci } 63448c2ecf20Sopenharmony_ci 63458c2ecf20Sopenharmony_ci if (!bp->num_req_tx_rings) 63468c2ecf20Sopenharmony_ci bp->num_tx_rings = rounddown_pow_of_two(bp->irq_nvecs); 63478c2ecf20Sopenharmony_ci else 63488c2ecf20Sopenharmony_ci bp->num_tx_rings = min(bp->irq_nvecs, bp->num_req_tx_rings); 63498c2ecf20Sopenharmony_ci 63508c2ecf20Sopenharmony_ci if (!bp->num_req_rx_rings) 63518c2ecf20Sopenharmony_ci bp->num_rx_rings = bp->irq_nvecs; 63528c2ecf20Sopenharmony_ci else 63538c2ecf20Sopenharmony_ci bp->num_rx_rings = min(bp->irq_nvecs, bp->num_req_rx_rings); 63548c2ecf20Sopenharmony_ci 63558c2ecf20Sopenharmony_ci netif_set_real_num_tx_queues(bp->dev, bp->num_tx_rings); 63568c2ecf20Sopenharmony_ci 63578c2ecf20Sopenharmony_ci return netif_set_real_num_rx_queues(bp->dev, bp->num_rx_rings); 63588c2ecf20Sopenharmony_ci} 63598c2ecf20Sopenharmony_ci 63608c2ecf20Sopenharmony_ci/* Called with rtnl_lock */ 63618c2ecf20Sopenharmony_cistatic int 63628c2ecf20Sopenharmony_cibnx2_open(struct net_device *dev) 63638c2ecf20Sopenharmony_ci{ 63648c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 63658c2ecf20Sopenharmony_ci int rc; 63668c2ecf20Sopenharmony_ci 63678c2ecf20Sopenharmony_ci rc = bnx2_request_firmware(bp); 63688c2ecf20Sopenharmony_ci if (rc < 0) 63698c2ecf20Sopenharmony_ci goto out; 63708c2ecf20Sopenharmony_ci 63718c2ecf20Sopenharmony_ci netif_carrier_off(dev); 63728c2ecf20Sopenharmony_ci 63738c2ecf20Sopenharmony_ci bnx2_disable_int(bp); 63748c2ecf20Sopenharmony_ci 63758c2ecf20Sopenharmony_ci rc = bnx2_setup_int_mode(bp, disable_msi); 63768c2ecf20Sopenharmony_ci if (rc) 63778c2ecf20Sopenharmony_ci goto open_err; 63788c2ecf20Sopenharmony_ci bnx2_init_napi(bp); 63798c2ecf20Sopenharmony_ci bnx2_napi_enable(bp); 63808c2ecf20Sopenharmony_ci rc = bnx2_alloc_mem(bp); 63818c2ecf20Sopenharmony_ci if (rc) 63828c2ecf20Sopenharmony_ci goto open_err; 63838c2ecf20Sopenharmony_ci 63848c2ecf20Sopenharmony_ci rc = bnx2_request_irq(bp); 63858c2ecf20Sopenharmony_ci if (rc) 63868c2ecf20Sopenharmony_ci goto open_err; 63878c2ecf20Sopenharmony_ci 63888c2ecf20Sopenharmony_ci rc = bnx2_init_nic(bp, 1); 63898c2ecf20Sopenharmony_ci if (rc) 63908c2ecf20Sopenharmony_ci goto open_err; 63918c2ecf20Sopenharmony_ci 63928c2ecf20Sopenharmony_ci mod_timer(&bp->timer, jiffies + bp->current_interval); 63938c2ecf20Sopenharmony_ci 63948c2ecf20Sopenharmony_ci atomic_set(&bp->intr_sem, 0); 63958c2ecf20Sopenharmony_ci 63968c2ecf20Sopenharmony_ci memset(bp->temp_stats_blk, 0, sizeof(struct statistics_block)); 63978c2ecf20Sopenharmony_ci 63988c2ecf20Sopenharmony_ci bnx2_enable_int(bp); 63998c2ecf20Sopenharmony_ci 64008c2ecf20Sopenharmony_ci if (bp->flags & BNX2_FLAG_USING_MSI) { 64018c2ecf20Sopenharmony_ci /* Test MSI to make sure it is working 64028c2ecf20Sopenharmony_ci * If MSI test fails, go back to INTx mode 64038c2ecf20Sopenharmony_ci */ 64048c2ecf20Sopenharmony_ci if (bnx2_test_intr(bp) != 0) { 64058c2ecf20Sopenharmony_ci netdev_warn(bp->dev, "No interrupt was generated using MSI, switching to INTx mode. Please report this failure to the PCI maintainer and include system chipset information.\n"); 64068c2ecf20Sopenharmony_ci 64078c2ecf20Sopenharmony_ci bnx2_disable_int(bp); 64088c2ecf20Sopenharmony_ci bnx2_free_irq(bp); 64098c2ecf20Sopenharmony_ci 64108c2ecf20Sopenharmony_ci bnx2_setup_int_mode(bp, 1); 64118c2ecf20Sopenharmony_ci 64128c2ecf20Sopenharmony_ci rc = bnx2_init_nic(bp, 0); 64138c2ecf20Sopenharmony_ci 64148c2ecf20Sopenharmony_ci if (!rc) 64158c2ecf20Sopenharmony_ci rc = bnx2_request_irq(bp); 64168c2ecf20Sopenharmony_ci 64178c2ecf20Sopenharmony_ci if (rc) { 64188c2ecf20Sopenharmony_ci del_timer_sync(&bp->timer); 64198c2ecf20Sopenharmony_ci goto open_err; 64208c2ecf20Sopenharmony_ci } 64218c2ecf20Sopenharmony_ci bnx2_enable_int(bp); 64228c2ecf20Sopenharmony_ci } 64238c2ecf20Sopenharmony_ci } 64248c2ecf20Sopenharmony_ci if (bp->flags & BNX2_FLAG_USING_MSI) 64258c2ecf20Sopenharmony_ci netdev_info(dev, "using MSI\n"); 64268c2ecf20Sopenharmony_ci else if (bp->flags & BNX2_FLAG_USING_MSIX) 64278c2ecf20Sopenharmony_ci netdev_info(dev, "using MSIX\n"); 64288c2ecf20Sopenharmony_ci 64298c2ecf20Sopenharmony_ci netif_tx_start_all_queues(dev); 64308c2ecf20Sopenharmony_ciout: 64318c2ecf20Sopenharmony_ci return rc; 64328c2ecf20Sopenharmony_ci 64338c2ecf20Sopenharmony_ciopen_err: 64348c2ecf20Sopenharmony_ci bnx2_napi_disable(bp); 64358c2ecf20Sopenharmony_ci bnx2_free_skbs(bp); 64368c2ecf20Sopenharmony_ci bnx2_free_irq(bp); 64378c2ecf20Sopenharmony_ci bnx2_free_mem(bp); 64388c2ecf20Sopenharmony_ci bnx2_del_napi(bp); 64398c2ecf20Sopenharmony_ci bnx2_release_firmware(bp); 64408c2ecf20Sopenharmony_ci goto out; 64418c2ecf20Sopenharmony_ci} 64428c2ecf20Sopenharmony_ci 64438c2ecf20Sopenharmony_cistatic void 64448c2ecf20Sopenharmony_cibnx2_reset_task(struct work_struct *work) 64458c2ecf20Sopenharmony_ci{ 64468c2ecf20Sopenharmony_ci struct bnx2 *bp = container_of(work, struct bnx2, reset_task); 64478c2ecf20Sopenharmony_ci int rc; 64488c2ecf20Sopenharmony_ci u16 pcicmd; 64498c2ecf20Sopenharmony_ci 64508c2ecf20Sopenharmony_ci rtnl_lock(); 64518c2ecf20Sopenharmony_ci if (!netif_running(bp->dev)) { 64528c2ecf20Sopenharmony_ci rtnl_unlock(); 64538c2ecf20Sopenharmony_ci return; 64548c2ecf20Sopenharmony_ci } 64558c2ecf20Sopenharmony_ci 64568c2ecf20Sopenharmony_ci bnx2_netif_stop(bp, true); 64578c2ecf20Sopenharmony_ci 64588c2ecf20Sopenharmony_ci pci_read_config_word(bp->pdev, PCI_COMMAND, &pcicmd); 64598c2ecf20Sopenharmony_ci if (!(pcicmd & PCI_COMMAND_MEMORY)) { 64608c2ecf20Sopenharmony_ci /* in case PCI block has reset */ 64618c2ecf20Sopenharmony_ci pci_restore_state(bp->pdev); 64628c2ecf20Sopenharmony_ci pci_save_state(bp->pdev); 64638c2ecf20Sopenharmony_ci } 64648c2ecf20Sopenharmony_ci rc = bnx2_init_nic(bp, 1); 64658c2ecf20Sopenharmony_ci if (rc) { 64668c2ecf20Sopenharmony_ci netdev_err(bp->dev, "failed to reset NIC, closing\n"); 64678c2ecf20Sopenharmony_ci bnx2_napi_enable(bp); 64688c2ecf20Sopenharmony_ci dev_close(bp->dev); 64698c2ecf20Sopenharmony_ci rtnl_unlock(); 64708c2ecf20Sopenharmony_ci return; 64718c2ecf20Sopenharmony_ci } 64728c2ecf20Sopenharmony_ci 64738c2ecf20Sopenharmony_ci atomic_set(&bp->intr_sem, 1); 64748c2ecf20Sopenharmony_ci bnx2_netif_start(bp, true); 64758c2ecf20Sopenharmony_ci rtnl_unlock(); 64768c2ecf20Sopenharmony_ci} 64778c2ecf20Sopenharmony_ci 64788c2ecf20Sopenharmony_ci#define BNX2_FTQ_ENTRY(ftq) { __stringify(ftq##FTQ_CTL), BNX2_##ftq##FTQ_CTL } 64798c2ecf20Sopenharmony_ci 64808c2ecf20Sopenharmony_cistatic void 64818c2ecf20Sopenharmony_cibnx2_dump_ftq(struct bnx2 *bp) 64828c2ecf20Sopenharmony_ci{ 64838c2ecf20Sopenharmony_ci int i; 64848c2ecf20Sopenharmony_ci u32 reg, bdidx, cid, valid; 64858c2ecf20Sopenharmony_ci struct net_device *dev = bp->dev; 64868c2ecf20Sopenharmony_ci static const struct ftq_reg { 64878c2ecf20Sopenharmony_ci char *name; 64888c2ecf20Sopenharmony_ci u32 off; 64898c2ecf20Sopenharmony_ci } ftq_arr[] = { 64908c2ecf20Sopenharmony_ci BNX2_FTQ_ENTRY(RV2P_P), 64918c2ecf20Sopenharmony_ci BNX2_FTQ_ENTRY(RV2P_T), 64928c2ecf20Sopenharmony_ci BNX2_FTQ_ENTRY(RV2P_M), 64938c2ecf20Sopenharmony_ci BNX2_FTQ_ENTRY(TBDR_), 64948c2ecf20Sopenharmony_ci BNX2_FTQ_ENTRY(TDMA_), 64958c2ecf20Sopenharmony_ci BNX2_FTQ_ENTRY(TXP_), 64968c2ecf20Sopenharmony_ci BNX2_FTQ_ENTRY(TXP_), 64978c2ecf20Sopenharmony_ci BNX2_FTQ_ENTRY(TPAT_), 64988c2ecf20Sopenharmony_ci BNX2_FTQ_ENTRY(RXP_C), 64998c2ecf20Sopenharmony_ci BNX2_FTQ_ENTRY(RXP_), 65008c2ecf20Sopenharmony_ci BNX2_FTQ_ENTRY(COM_COMXQ_), 65018c2ecf20Sopenharmony_ci BNX2_FTQ_ENTRY(COM_COMTQ_), 65028c2ecf20Sopenharmony_ci BNX2_FTQ_ENTRY(COM_COMQ_), 65038c2ecf20Sopenharmony_ci BNX2_FTQ_ENTRY(CP_CPQ_), 65048c2ecf20Sopenharmony_ci }; 65058c2ecf20Sopenharmony_ci 65068c2ecf20Sopenharmony_ci netdev_err(dev, "<--- start FTQ dump --->\n"); 65078c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ftq_arr); i++) 65088c2ecf20Sopenharmony_ci netdev_err(dev, "%s %08x\n", ftq_arr[i].name, 65098c2ecf20Sopenharmony_ci bnx2_reg_rd_ind(bp, ftq_arr[i].off)); 65108c2ecf20Sopenharmony_ci 65118c2ecf20Sopenharmony_ci netdev_err(dev, "CPU states:\n"); 65128c2ecf20Sopenharmony_ci for (reg = BNX2_TXP_CPU_MODE; reg <= BNX2_CP_CPU_MODE; reg += 0x40000) 65138c2ecf20Sopenharmony_ci netdev_err(dev, "%06x mode %x state %x evt_mask %x pc %x pc %x instr %x\n", 65148c2ecf20Sopenharmony_ci reg, bnx2_reg_rd_ind(bp, reg), 65158c2ecf20Sopenharmony_ci bnx2_reg_rd_ind(bp, reg + 4), 65168c2ecf20Sopenharmony_ci bnx2_reg_rd_ind(bp, reg + 8), 65178c2ecf20Sopenharmony_ci bnx2_reg_rd_ind(bp, reg + 0x1c), 65188c2ecf20Sopenharmony_ci bnx2_reg_rd_ind(bp, reg + 0x1c), 65198c2ecf20Sopenharmony_ci bnx2_reg_rd_ind(bp, reg + 0x20)); 65208c2ecf20Sopenharmony_ci 65218c2ecf20Sopenharmony_ci netdev_err(dev, "<--- end FTQ dump --->\n"); 65228c2ecf20Sopenharmony_ci netdev_err(dev, "<--- start TBDC dump --->\n"); 65238c2ecf20Sopenharmony_ci netdev_err(dev, "TBDC free cnt: %ld\n", 65248c2ecf20Sopenharmony_ci BNX2_RD(bp, BNX2_TBDC_STATUS) & BNX2_TBDC_STATUS_FREE_CNT); 65258c2ecf20Sopenharmony_ci netdev_err(dev, "LINE CID BIDX CMD VALIDS\n"); 65268c2ecf20Sopenharmony_ci for (i = 0; i < 0x20; i++) { 65278c2ecf20Sopenharmony_ci int j = 0; 65288c2ecf20Sopenharmony_ci 65298c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_TBDC_BD_ADDR, i); 65308c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_TBDC_CAM_OPCODE, 65318c2ecf20Sopenharmony_ci BNX2_TBDC_CAM_OPCODE_OPCODE_CAM_READ); 65328c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_TBDC_COMMAND, BNX2_TBDC_COMMAND_CMD_REG_ARB); 65338c2ecf20Sopenharmony_ci while ((BNX2_RD(bp, BNX2_TBDC_COMMAND) & 65348c2ecf20Sopenharmony_ci BNX2_TBDC_COMMAND_CMD_REG_ARB) && j < 100) 65358c2ecf20Sopenharmony_ci j++; 65368c2ecf20Sopenharmony_ci 65378c2ecf20Sopenharmony_ci cid = BNX2_RD(bp, BNX2_TBDC_CID); 65388c2ecf20Sopenharmony_ci bdidx = BNX2_RD(bp, BNX2_TBDC_BIDX); 65398c2ecf20Sopenharmony_ci valid = BNX2_RD(bp, BNX2_TBDC_CAM_OPCODE); 65408c2ecf20Sopenharmony_ci netdev_err(dev, "%02x %06x %04lx %02x [%x]\n", 65418c2ecf20Sopenharmony_ci i, cid, bdidx & BNX2_TBDC_BDIDX_BDIDX, 65428c2ecf20Sopenharmony_ci bdidx >> 24, (valid >> 8) & 0x0ff); 65438c2ecf20Sopenharmony_ci } 65448c2ecf20Sopenharmony_ci netdev_err(dev, "<--- end TBDC dump --->\n"); 65458c2ecf20Sopenharmony_ci} 65468c2ecf20Sopenharmony_ci 65478c2ecf20Sopenharmony_cistatic void 65488c2ecf20Sopenharmony_cibnx2_dump_state(struct bnx2 *bp) 65498c2ecf20Sopenharmony_ci{ 65508c2ecf20Sopenharmony_ci struct net_device *dev = bp->dev; 65518c2ecf20Sopenharmony_ci u32 val1, val2; 65528c2ecf20Sopenharmony_ci 65538c2ecf20Sopenharmony_ci pci_read_config_dword(bp->pdev, PCI_COMMAND, &val1); 65548c2ecf20Sopenharmony_ci netdev_err(dev, "DEBUG: intr_sem[%x] PCI_CMD[%08x]\n", 65558c2ecf20Sopenharmony_ci atomic_read(&bp->intr_sem), val1); 65568c2ecf20Sopenharmony_ci pci_read_config_dword(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &val1); 65578c2ecf20Sopenharmony_ci pci_read_config_dword(bp->pdev, BNX2_PCICFG_MISC_CONFIG, &val2); 65588c2ecf20Sopenharmony_ci netdev_err(dev, "DEBUG: PCI_PM[%08x] PCI_MISC_CFG[%08x]\n", val1, val2); 65598c2ecf20Sopenharmony_ci netdev_err(dev, "DEBUG: EMAC_TX_STATUS[%08x] EMAC_RX_STATUS[%08x]\n", 65608c2ecf20Sopenharmony_ci BNX2_RD(bp, BNX2_EMAC_TX_STATUS), 65618c2ecf20Sopenharmony_ci BNX2_RD(bp, BNX2_EMAC_RX_STATUS)); 65628c2ecf20Sopenharmony_ci netdev_err(dev, "DEBUG: RPM_MGMT_PKT_CTRL[%08x]\n", 65638c2ecf20Sopenharmony_ci BNX2_RD(bp, BNX2_RPM_MGMT_PKT_CTRL)); 65648c2ecf20Sopenharmony_ci netdev_err(dev, "DEBUG: HC_STATS_INTERRUPT_STATUS[%08x]\n", 65658c2ecf20Sopenharmony_ci BNX2_RD(bp, BNX2_HC_STATS_INTERRUPT_STATUS)); 65668c2ecf20Sopenharmony_ci if (bp->flags & BNX2_FLAG_USING_MSIX) 65678c2ecf20Sopenharmony_ci netdev_err(dev, "DEBUG: PBA[%08x]\n", 65688c2ecf20Sopenharmony_ci BNX2_RD(bp, BNX2_PCI_GRC_WINDOW3_BASE)); 65698c2ecf20Sopenharmony_ci} 65708c2ecf20Sopenharmony_ci 65718c2ecf20Sopenharmony_cistatic void 65728c2ecf20Sopenharmony_cibnx2_tx_timeout(struct net_device *dev, unsigned int txqueue) 65738c2ecf20Sopenharmony_ci{ 65748c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 65758c2ecf20Sopenharmony_ci 65768c2ecf20Sopenharmony_ci bnx2_dump_ftq(bp); 65778c2ecf20Sopenharmony_ci bnx2_dump_state(bp); 65788c2ecf20Sopenharmony_ci bnx2_dump_mcp_state(bp); 65798c2ecf20Sopenharmony_ci 65808c2ecf20Sopenharmony_ci /* This allows the netif to be shutdown gracefully before resetting */ 65818c2ecf20Sopenharmony_ci schedule_work(&bp->reset_task); 65828c2ecf20Sopenharmony_ci} 65838c2ecf20Sopenharmony_ci 65848c2ecf20Sopenharmony_ci/* Called with netif_tx_lock. 65858c2ecf20Sopenharmony_ci * bnx2_tx_int() runs without netif_tx_lock unless it needs to call 65868c2ecf20Sopenharmony_ci * netif_wake_queue(). 65878c2ecf20Sopenharmony_ci */ 65888c2ecf20Sopenharmony_cistatic netdev_tx_t 65898c2ecf20Sopenharmony_cibnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) 65908c2ecf20Sopenharmony_ci{ 65918c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 65928c2ecf20Sopenharmony_ci dma_addr_t mapping; 65938c2ecf20Sopenharmony_ci struct bnx2_tx_bd *txbd; 65948c2ecf20Sopenharmony_ci struct bnx2_sw_tx_bd *tx_buf; 65958c2ecf20Sopenharmony_ci u32 len, vlan_tag_flags, last_frag, mss; 65968c2ecf20Sopenharmony_ci u16 prod, ring_prod; 65978c2ecf20Sopenharmony_ci int i; 65988c2ecf20Sopenharmony_ci struct bnx2_napi *bnapi; 65998c2ecf20Sopenharmony_ci struct bnx2_tx_ring_info *txr; 66008c2ecf20Sopenharmony_ci struct netdev_queue *txq; 66018c2ecf20Sopenharmony_ci 66028c2ecf20Sopenharmony_ci /* Determine which tx ring we will be placed on */ 66038c2ecf20Sopenharmony_ci i = skb_get_queue_mapping(skb); 66048c2ecf20Sopenharmony_ci bnapi = &bp->bnx2_napi[i]; 66058c2ecf20Sopenharmony_ci txr = &bnapi->tx_ring; 66068c2ecf20Sopenharmony_ci txq = netdev_get_tx_queue(dev, i); 66078c2ecf20Sopenharmony_ci 66088c2ecf20Sopenharmony_ci if (unlikely(bnx2_tx_avail(bp, txr) < 66098c2ecf20Sopenharmony_ci (skb_shinfo(skb)->nr_frags + 1))) { 66108c2ecf20Sopenharmony_ci netif_tx_stop_queue(txq); 66118c2ecf20Sopenharmony_ci netdev_err(dev, "BUG! Tx ring full when queue awake!\n"); 66128c2ecf20Sopenharmony_ci 66138c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 66148c2ecf20Sopenharmony_ci } 66158c2ecf20Sopenharmony_ci len = skb_headlen(skb); 66168c2ecf20Sopenharmony_ci prod = txr->tx_prod; 66178c2ecf20Sopenharmony_ci ring_prod = BNX2_TX_RING_IDX(prod); 66188c2ecf20Sopenharmony_ci 66198c2ecf20Sopenharmony_ci vlan_tag_flags = 0; 66208c2ecf20Sopenharmony_ci if (skb->ip_summed == CHECKSUM_PARTIAL) { 66218c2ecf20Sopenharmony_ci vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM; 66228c2ecf20Sopenharmony_ci } 66238c2ecf20Sopenharmony_ci 66248c2ecf20Sopenharmony_ci if (skb_vlan_tag_present(skb)) { 66258c2ecf20Sopenharmony_ci vlan_tag_flags |= 66268c2ecf20Sopenharmony_ci (TX_BD_FLAGS_VLAN_TAG | (skb_vlan_tag_get(skb) << 16)); 66278c2ecf20Sopenharmony_ci } 66288c2ecf20Sopenharmony_ci 66298c2ecf20Sopenharmony_ci if ((mss = skb_shinfo(skb)->gso_size)) { 66308c2ecf20Sopenharmony_ci u32 tcp_opt_len; 66318c2ecf20Sopenharmony_ci struct iphdr *iph; 66328c2ecf20Sopenharmony_ci 66338c2ecf20Sopenharmony_ci vlan_tag_flags |= TX_BD_FLAGS_SW_LSO; 66348c2ecf20Sopenharmony_ci 66358c2ecf20Sopenharmony_ci tcp_opt_len = tcp_optlen(skb); 66368c2ecf20Sopenharmony_ci 66378c2ecf20Sopenharmony_ci if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) { 66388c2ecf20Sopenharmony_ci u32 tcp_off = skb_transport_offset(skb) - 66398c2ecf20Sopenharmony_ci sizeof(struct ipv6hdr) - ETH_HLEN; 66408c2ecf20Sopenharmony_ci 66418c2ecf20Sopenharmony_ci vlan_tag_flags |= ((tcp_opt_len >> 2) << 8) | 66428c2ecf20Sopenharmony_ci TX_BD_FLAGS_SW_FLAGS; 66438c2ecf20Sopenharmony_ci if (likely(tcp_off == 0)) 66448c2ecf20Sopenharmony_ci vlan_tag_flags &= ~TX_BD_FLAGS_TCP6_OFF0_MSK; 66458c2ecf20Sopenharmony_ci else { 66468c2ecf20Sopenharmony_ci tcp_off >>= 3; 66478c2ecf20Sopenharmony_ci vlan_tag_flags |= ((tcp_off & 0x3) << 66488c2ecf20Sopenharmony_ci TX_BD_FLAGS_TCP6_OFF0_SHL) | 66498c2ecf20Sopenharmony_ci ((tcp_off & 0x10) << 66508c2ecf20Sopenharmony_ci TX_BD_FLAGS_TCP6_OFF4_SHL); 66518c2ecf20Sopenharmony_ci mss |= (tcp_off & 0xc) << TX_BD_TCP6_OFF2_SHL; 66528c2ecf20Sopenharmony_ci } 66538c2ecf20Sopenharmony_ci } else { 66548c2ecf20Sopenharmony_ci iph = ip_hdr(skb); 66558c2ecf20Sopenharmony_ci if (tcp_opt_len || (iph->ihl > 5)) { 66568c2ecf20Sopenharmony_ci vlan_tag_flags |= ((iph->ihl - 5) + 66578c2ecf20Sopenharmony_ci (tcp_opt_len >> 2)) << 8; 66588c2ecf20Sopenharmony_ci } 66598c2ecf20Sopenharmony_ci } 66608c2ecf20Sopenharmony_ci } else 66618c2ecf20Sopenharmony_ci mss = 0; 66628c2ecf20Sopenharmony_ci 66638c2ecf20Sopenharmony_ci mapping = dma_map_single(&bp->pdev->dev, skb->data, len, PCI_DMA_TODEVICE); 66648c2ecf20Sopenharmony_ci if (dma_mapping_error(&bp->pdev->dev, mapping)) { 66658c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 66668c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 66678c2ecf20Sopenharmony_ci } 66688c2ecf20Sopenharmony_ci 66698c2ecf20Sopenharmony_ci tx_buf = &txr->tx_buf_ring[ring_prod]; 66708c2ecf20Sopenharmony_ci tx_buf->skb = skb; 66718c2ecf20Sopenharmony_ci dma_unmap_addr_set(tx_buf, mapping, mapping); 66728c2ecf20Sopenharmony_ci 66738c2ecf20Sopenharmony_ci txbd = &txr->tx_desc_ring[ring_prod]; 66748c2ecf20Sopenharmony_ci 66758c2ecf20Sopenharmony_ci txbd->tx_bd_haddr_hi = (u64) mapping >> 32; 66768c2ecf20Sopenharmony_ci txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff; 66778c2ecf20Sopenharmony_ci txbd->tx_bd_mss_nbytes = len | (mss << 16); 66788c2ecf20Sopenharmony_ci txbd->tx_bd_vlan_tag_flags = vlan_tag_flags | TX_BD_FLAGS_START; 66798c2ecf20Sopenharmony_ci 66808c2ecf20Sopenharmony_ci last_frag = skb_shinfo(skb)->nr_frags; 66818c2ecf20Sopenharmony_ci tx_buf->nr_frags = last_frag; 66828c2ecf20Sopenharmony_ci tx_buf->is_gso = skb_is_gso(skb); 66838c2ecf20Sopenharmony_ci 66848c2ecf20Sopenharmony_ci for (i = 0; i < last_frag; i++) { 66858c2ecf20Sopenharmony_ci const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; 66868c2ecf20Sopenharmony_ci 66878c2ecf20Sopenharmony_ci prod = BNX2_NEXT_TX_BD(prod); 66888c2ecf20Sopenharmony_ci ring_prod = BNX2_TX_RING_IDX(prod); 66898c2ecf20Sopenharmony_ci txbd = &txr->tx_desc_ring[ring_prod]; 66908c2ecf20Sopenharmony_ci 66918c2ecf20Sopenharmony_ci len = skb_frag_size(frag); 66928c2ecf20Sopenharmony_ci mapping = skb_frag_dma_map(&bp->pdev->dev, frag, 0, len, 66938c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 66948c2ecf20Sopenharmony_ci if (dma_mapping_error(&bp->pdev->dev, mapping)) 66958c2ecf20Sopenharmony_ci goto dma_error; 66968c2ecf20Sopenharmony_ci dma_unmap_addr_set(&txr->tx_buf_ring[ring_prod], mapping, 66978c2ecf20Sopenharmony_ci mapping); 66988c2ecf20Sopenharmony_ci 66998c2ecf20Sopenharmony_ci txbd->tx_bd_haddr_hi = (u64) mapping >> 32; 67008c2ecf20Sopenharmony_ci txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff; 67018c2ecf20Sopenharmony_ci txbd->tx_bd_mss_nbytes = len | (mss << 16); 67028c2ecf20Sopenharmony_ci txbd->tx_bd_vlan_tag_flags = vlan_tag_flags; 67038c2ecf20Sopenharmony_ci 67048c2ecf20Sopenharmony_ci } 67058c2ecf20Sopenharmony_ci txbd->tx_bd_vlan_tag_flags |= TX_BD_FLAGS_END; 67068c2ecf20Sopenharmony_ci 67078c2ecf20Sopenharmony_ci /* Sync BD data before updating TX mailbox */ 67088c2ecf20Sopenharmony_ci wmb(); 67098c2ecf20Sopenharmony_ci 67108c2ecf20Sopenharmony_ci netdev_tx_sent_queue(txq, skb->len); 67118c2ecf20Sopenharmony_ci 67128c2ecf20Sopenharmony_ci prod = BNX2_NEXT_TX_BD(prod); 67138c2ecf20Sopenharmony_ci txr->tx_prod_bseq += skb->len; 67148c2ecf20Sopenharmony_ci 67158c2ecf20Sopenharmony_ci BNX2_WR16(bp, txr->tx_bidx_addr, prod); 67168c2ecf20Sopenharmony_ci BNX2_WR(bp, txr->tx_bseq_addr, txr->tx_prod_bseq); 67178c2ecf20Sopenharmony_ci 67188c2ecf20Sopenharmony_ci txr->tx_prod = prod; 67198c2ecf20Sopenharmony_ci 67208c2ecf20Sopenharmony_ci if (unlikely(bnx2_tx_avail(bp, txr) <= MAX_SKB_FRAGS)) { 67218c2ecf20Sopenharmony_ci netif_tx_stop_queue(txq); 67228c2ecf20Sopenharmony_ci 67238c2ecf20Sopenharmony_ci /* netif_tx_stop_queue() must be done before checking 67248c2ecf20Sopenharmony_ci * tx index in bnx2_tx_avail() below, because in 67258c2ecf20Sopenharmony_ci * bnx2_tx_int(), we update tx index before checking for 67268c2ecf20Sopenharmony_ci * netif_tx_queue_stopped(). 67278c2ecf20Sopenharmony_ci */ 67288c2ecf20Sopenharmony_ci smp_mb(); 67298c2ecf20Sopenharmony_ci if (bnx2_tx_avail(bp, txr) > bp->tx_wake_thresh) 67308c2ecf20Sopenharmony_ci netif_tx_wake_queue(txq); 67318c2ecf20Sopenharmony_ci } 67328c2ecf20Sopenharmony_ci 67338c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 67348c2ecf20Sopenharmony_cidma_error: 67358c2ecf20Sopenharmony_ci /* save value of frag that failed */ 67368c2ecf20Sopenharmony_ci last_frag = i; 67378c2ecf20Sopenharmony_ci 67388c2ecf20Sopenharmony_ci /* start back at beginning and unmap skb */ 67398c2ecf20Sopenharmony_ci prod = txr->tx_prod; 67408c2ecf20Sopenharmony_ci ring_prod = BNX2_TX_RING_IDX(prod); 67418c2ecf20Sopenharmony_ci tx_buf = &txr->tx_buf_ring[ring_prod]; 67428c2ecf20Sopenharmony_ci tx_buf->skb = NULL; 67438c2ecf20Sopenharmony_ci dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(tx_buf, mapping), 67448c2ecf20Sopenharmony_ci skb_headlen(skb), PCI_DMA_TODEVICE); 67458c2ecf20Sopenharmony_ci 67468c2ecf20Sopenharmony_ci /* unmap remaining mapped pages */ 67478c2ecf20Sopenharmony_ci for (i = 0; i < last_frag; i++) { 67488c2ecf20Sopenharmony_ci prod = BNX2_NEXT_TX_BD(prod); 67498c2ecf20Sopenharmony_ci ring_prod = BNX2_TX_RING_IDX(prod); 67508c2ecf20Sopenharmony_ci tx_buf = &txr->tx_buf_ring[ring_prod]; 67518c2ecf20Sopenharmony_ci dma_unmap_page(&bp->pdev->dev, dma_unmap_addr(tx_buf, mapping), 67528c2ecf20Sopenharmony_ci skb_frag_size(&skb_shinfo(skb)->frags[i]), 67538c2ecf20Sopenharmony_ci PCI_DMA_TODEVICE); 67548c2ecf20Sopenharmony_ci } 67558c2ecf20Sopenharmony_ci 67568c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 67578c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 67588c2ecf20Sopenharmony_ci} 67598c2ecf20Sopenharmony_ci 67608c2ecf20Sopenharmony_ci/* Called with rtnl_lock */ 67618c2ecf20Sopenharmony_cistatic int 67628c2ecf20Sopenharmony_cibnx2_close(struct net_device *dev) 67638c2ecf20Sopenharmony_ci{ 67648c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 67658c2ecf20Sopenharmony_ci 67668c2ecf20Sopenharmony_ci bnx2_disable_int_sync(bp); 67678c2ecf20Sopenharmony_ci bnx2_napi_disable(bp); 67688c2ecf20Sopenharmony_ci netif_tx_disable(dev); 67698c2ecf20Sopenharmony_ci del_timer_sync(&bp->timer); 67708c2ecf20Sopenharmony_ci bnx2_shutdown_chip(bp); 67718c2ecf20Sopenharmony_ci bnx2_free_irq(bp); 67728c2ecf20Sopenharmony_ci bnx2_free_skbs(bp); 67738c2ecf20Sopenharmony_ci bnx2_free_mem(bp); 67748c2ecf20Sopenharmony_ci bnx2_del_napi(bp); 67758c2ecf20Sopenharmony_ci bp->link_up = 0; 67768c2ecf20Sopenharmony_ci netif_carrier_off(bp->dev); 67778c2ecf20Sopenharmony_ci return 0; 67788c2ecf20Sopenharmony_ci} 67798c2ecf20Sopenharmony_ci 67808c2ecf20Sopenharmony_cistatic void 67818c2ecf20Sopenharmony_cibnx2_save_stats(struct bnx2 *bp) 67828c2ecf20Sopenharmony_ci{ 67838c2ecf20Sopenharmony_ci u32 *hw_stats = (u32 *) bp->stats_blk; 67848c2ecf20Sopenharmony_ci u32 *temp_stats = (u32 *) bp->temp_stats_blk; 67858c2ecf20Sopenharmony_ci int i; 67868c2ecf20Sopenharmony_ci 67878c2ecf20Sopenharmony_ci /* The 1st 10 counters are 64-bit counters */ 67888c2ecf20Sopenharmony_ci for (i = 0; i < 20; i += 2) { 67898c2ecf20Sopenharmony_ci u32 hi; 67908c2ecf20Sopenharmony_ci u64 lo; 67918c2ecf20Sopenharmony_ci 67928c2ecf20Sopenharmony_ci hi = temp_stats[i] + hw_stats[i]; 67938c2ecf20Sopenharmony_ci lo = (u64) temp_stats[i + 1] + (u64) hw_stats[i + 1]; 67948c2ecf20Sopenharmony_ci if (lo > 0xffffffff) 67958c2ecf20Sopenharmony_ci hi++; 67968c2ecf20Sopenharmony_ci temp_stats[i] = hi; 67978c2ecf20Sopenharmony_ci temp_stats[i + 1] = lo & 0xffffffff; 67988c2ecf20Sopenharmony_ci } 67998c2ecf20Sopenharmony_ci 68008c2ecf20Sopenharmony_ci for ( ; i < sizeof(struct statistics_block) / 4; i++) 68018c2ecf20Sopenharmony_ci temp_stats[i] += hw_stats[i]; 68028c2ecf20Sopenharmony_ci} 68038c2ecf20Sopenharmony_ci 68048c2ecf20Sopenharmony_ci#define GET_64BIT_NET_STATS64(ctr) \ 68058c2ecf20Sopenharmony_ci (((u64) (ctr##_hi) << 32) + (u64) (ctr##_lo)) 68068c2ecf20Sopenharmony_ci 68078c2ecf20Sopenharmony_ci#define GET_64BIT_NET_STATS(ctr) \ 68088c2ecf20Sopenharmony_ci GET_64BIT_NET_STATS64(bp->stats_blk->ctr) + \ 68098c2ecf20Sopenharmony_ci GET_64BIT_NET_STATS64(bp->temp_stats_blk->ctr) 68108c2ecf20Sopenharmony_ci 68118c2ecf20Sopenharmony_ci#define GET_32BIT_NET_STATS(ctr) \ 68128c2ecf20Sopenharmony_ci (unsigned long) (bp->stats_blk->ctr + \ 68138c2ecf20Sopenharmony_ci bp->temp_stats_blk->ctr) 68148c2ecf20Sopenharmony_ci 68158c2ecf20Sopenharmony_cistatic void 68168c2ecf20Sopenharmony_cibnx2_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *net_stats) 68178c2ecf20Sopenharmony_ci{ 68188c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 68198c2ecf20Sopenharmony_ci 68208c2ecf20Sopenharmony_ci if (!bp->stats_blk) 68218c2ecf20Sopenharmony_ci return; 68228c2ecf20Sopenharmony_ci 68238c2ecf20Sopenharmony_ci net_stats->rx_packets = 68248c2ecf20Sopenharmony_ci GET_64BIT_NET_STATS(stat_IfHCInUcastPkts) + 68258c2ecf20Sopenharmony_ci GET_64BIT_NET_STATS(stat_IfHCInMulticastPkts) + 68268c2ecf20Sopenharmony_ci GET_64BIT_NET_STATS(stat_IfHCInBroadcastPkts); 68278c2ecf20Sopenharmony_ci 68288c2ecf20Sopenharmony_ci net_stats->tx_packets = 68298c2ecf20Sopenharmony_ci GET_64BIT_NET_STATS(stat_IfHCOutUcastPkts) + 68308c2ecf20Sopenharmony_ci GET_64BIT_NET_STATS(stat_IfHCOutMulticastPkts) + 68318c2ecf20Sopenharmony_ci GET_64BIT_NET_STATS(stat_IfHCOutBroadcastPkts); 68328c2ecf20Sopenharmony_ci 68338c2ecf20Sopenharmony_ci net_stats->rx_bytes = 68348c2ecf20Sopenharmony_ci GET_64BIT_NET_STATS(stat_IfHCInOctets); 68358c2ecf20Sopenharmony_ci 68368c2ecf20Sopenharmony_ci net_stats->tx_bytes = 68378c2ecf20Sopenharmony_ci GET_64BIT_NET_STATS(stat_IfHCOutOctets); 68388c2ecf20Sopenharmony_ci 68398c2ecf20Sopenharmony_ci net_stats->multicast = 68408c2ecf20Sopenharmony_ci GET_64BIT_NET_STATS(stat_IfHCInMulticastPkts); 68418c2ecf20Sopenharmony_ci 68428c2ecf20Sopenharmony_ci net_stats->collisions = 68438c2ecf20Sopenharmony_ci GET_32BIT_NET_STATS(stat_EtherStatsCollisions); 68448c2ecf20Sopenharmony_ci 68458c2ecf20Sopenharmony_ci net_stats->rx_length_errors = 68468c2ecf20Sopenharmony_ci GET_32BIT_NET_STATS(stat_EtherStatsUndersizePkts) + 68478c2ecf20Sopenharmony_ci GET_32BIT_NET_STATS(stat_EtherStatsOverrsizePkts); 68488c2ecf20Sopenharmony_ci 68498c2ecf20Sopenharmony_ci net_stats->rx_over_errors = 68508c2ecf20Sopenharmony_ci GET_32BIT_NET_STATS(stat_IfInFTQDiscards) + 68518c2ecf20Sopenharmony_ci GET_32BIT_NET_STATS(stat_IfInMBUFDiscards); 68528c2ecf20Sopenharmony_ci 68538c2ecf20Sopenharmony_ci net_stats->rx_frame_errors = 68548c2ecf20Sopenharmony_ci GET_32BIT_NET_STATS(stat_Dot3StatsAlignmentErrors); 68558c2ecf20Sopenharmony_ci 68568c2ecf20Sopenharmony_ci net_stats->rx_crc_errors = 68578c2ecf20Sopenharmony_ci GET_32BIT_NET_STATS(stat_Dot3StatsFCSErrors); 68588c2ecf20Sopenharmony_ci 68598c2ecf20Sopenharmony_ci net_stats->rx_errors = net_stats->rx_length_errors + 68608c2ecf20Sopenharmony_ci net_stats->rx_over_errors + net_stats->rx_frame_errors + 68618c2ecf20Sopenharmony_ci net_stats->rx_crc_errors; 68628c2ecf20Sopenharmony_ci 68638c2ecf20Sopenharmony_ci net_stats->tx_aborted_errors = 68648c2ecf20Sopenharmony_ci GET_32BIT_NET_STATS(stat_Dot3StatsExcessiveCollisions) + 68658c2ecf20Sopenharmony_ci GET_32BIT_NET_STATS(stat_Dot3StatsLateCollisions); 68668c2ecf20Sopenharmony_ci 68678c2ecf20Sopenharmony_ci if ((BNX2_CHIP(bp) == BNX2_CHIP_5706) || 68688c2ecf20Sopenharmony_ci (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_A0)) 68698c2ecf20Sopenharmony_ci net_stats->tx_carrier_errors = 0; 68708c2ecf20Sopenharmony_ci else { 68718c2ecf20Sopenharmony_ci net_stats->tx_carrier_errors = 68728c2ecf20Sopenharmony_ci GET_32BIT_NET_STATS(stat_Dot3StatsCarrierSenseErrors); 68738c2ecf20Sopenharmony_ci } 68748c2ecf20Sopenharmony_ci 68758c2ecf20Sopenharmony_ci net_stats->tx_errors = 68768c2ecf20Sopenharmony_ci GET_32BIT_NET_STATS(stat_emac_tx_stat_dot3statsinternalmactransmiterrors) + 68778c2ecf20Sopenharmony_ci net_stats->tx_aborted_errors + 68788c2ecf20Sopenharmony_ci net_stats->tx_carrier_errors; 68798c2ecf20Sopenharmony_ci 68808c2ecf20Sopenharmony_ci net_stats->rx_missed_errors = 68818c2ecf20Sopenharmony_ci GET_32BIT_NET_STATS(stat_IfInFTQDiscards) + 68828c2ecf20Sopenharmony_ci GET_32BIT_NET_STATS(stat_IfInMBUFDiscards) + 68838c2ecf20Sopenharmony_ci GET_32BIT_NET_STATS(stat_FwRxDrop); 68848c2ecf20Sopenharmony_ci 68858c2ecf20Sopenharmony_ci} 68868c2ecf20Sopenharmony_ci 68878c2ecf20Sopenharmony_ci/* All ethtool functions called with rtnl_lock */ 68888c2ecf20Sopenharmony_ci 68898c2ecf20Sopenharmony_cistatic int 68908c2ecf20Sopenharmony_cibnx2_get_link_ksettings(struct net_device *dev, 68918c2ecf20Sopenharmony_ci struct ethtool_link_ksettings *cmd) 68928c2ecf20Sopenharmony_ci{ 68938c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 68948c2ecf20Sopenharmony_ci int support_serdes = 0, support_copper = 0; 68958c2ecf20Sopenharmony_ci u32 supported, advertising; 68968c2ecf20Sopenharmony_ci 68978c2ecf20Sopenharmony_ci supported = SUPPORTED_Autoneg; 68988c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) { 68998c2ecf20Sopenharmony_ci support_serdes = 1; 69008c2ecf20Sopenharmony_ci support_copper = 1; 69018c2ecf20Sopenharmony_ci } else if (bp->phy_port == PORT_FIBRE) 69028c2ecf20Sopenharmony_ci support_serdes = 1; 69038c2ecf20Sopenharmony_ci else 69048c2ecf20Sopenharmony_ci support_copper = 1; 69058c2ecf20Sopenharmony_ci 69068c2ecf20Sopenharmony_ci if (support_serdes) { 69078c2ecf20Sopenharmony_ci supported |= SUPPORTED_1000baseT_Full | 69088c2ecf20Sopenharmony_ci SUPPORTED_FIBRE; 69098c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE) 69108c2ecf20Sopenharmony_ci supported |= SUPPORTED_2500baseX_Full; 69118c2ecf20Sopenharmony_ci } 69128c2ecf20Sopenharmony_ci if (support_copper) { 69138c2ecf20Sopenharmony_ci supported |= SUPPORTED_10baseT_Half | 69148c2ecf20Sopenharmony_ci SUPPORTED_10baseT_Full | 69158c2ecf20Sopenharmony_ci SUPPORTED_100baseT_Half | 69168c2ecf20Sopenharmony_ci SUPPORTED_100baseT_Full | 69178c2ecf20Sopenharmony_ci SUPPORTED_1000baseT_Full | 69188c2ecf20Sopenharmony_ci SUPPORTED_TP; 69198c2ecf20Sopenharmony_ci } 69208c2ecf20Sopenharmony_ci 69218c2ecf20Sopenharmony_ci spin_lock_bh(&bp->phy_lock); 69228c2ecf20Sopenharmony_ci cmd->base.port = bp->phy_port; 69238c2ecf20Sopenharmony_ci advertising = bp->advertising; 69248c2ecf20Sopenharmony_ci 69258c2ecf20Sopenharmony_ci if (bp->autoneg & AUTONEG_SPEED) { 69268c2ecf20Sopenharmony_ci cmd->base.autoneg = AUTONEG_ENABLE; 69278c2ecf20Sopenharmony_ci } else { 69288c2ecf20Sopenharmony_ci cmd->base.autoneg = AUTONEG_DISABLE; 69298c2ecf20Sopenharmony_ci } 69308c2ecf20Sopenharmony_ci 69318c2ecf20Sopenharmony_ci if (netif_carrier_ok(dev)) { 69328c2ecf20Sopenharmony_ci cmd->base.speed = bp->line_speed; 69338c2ecf20Sopenharmony_ci cmd->base.duplex = bp->duplex; 69348c2ecf20Sopenharmony_ci if (!(bp->phy_flags & BNX2_PHY_FLAG_SERDES)) { 69358c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_MDIX) 69368c2ecf20Sopenharmony_ci cmd->base.eth_tp_mdix = ETH_TP_MDI_X; 69378c2ecf20Sopenharmony_ci else 69388c2ecf20Sopenharmony_ci cmd->base.eth_tp_mdix = ETH_TP_MDI; 69398c2ecf20Sopenharmony_ci } 69408c2ecf20Sopenharmony_ci } 69418c2ecf20Sopenharmony_ci else { 69428c2ecf20Sopenharmony_ci cmd->base.speed = SPEED_UNKNOWN; 69438c2ecf20Sopenharmony_ci cmd->base.duplex = DUPLEX_UNKNOWN; 69448c2ecf20Sopenharmony_ci } 69458c2ecf20Sopenharmony_ci spin_unlock_bh(&bp->phy_lock); 69468c2ecf20Sopenharmony_ci 69478c2ecf20Sopenharmony_ci cmd->base.phy_address = bp->phy_addr; 69488c2ecf20Sopenharmony_ci 69498c2ecf20Sopenharmony_ci ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, 69508c2ecf20Sopenharmony_ci supported); 69518c2ecf20Sopenharmony_ci ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising, 69528c2ecf20Sopenharmony_ci advertising); 69538c2ecf20Sopenharmony_ci 69548c2ecf20Sopenharmony_ci return 0; 69558c2ecf20Sopenharmony_ci} 69568c2ecf20Sopenharmony_ci 69578c2ecf20Sopenharmony_cistatic int 69588c2ecf20Sopenharmony_cibnx2_set_link_ksettings(struct net_device *dev, 69598c2ecf20Sopenharmony_ci const struct ethtool_link_ksettings *cmd) 69608c2ecf20Sopenharmony_ci{ 69618c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 69628c2ecf20Sopenharmony_ci u8 autoneg = bp->autoneg; 69638c2ecf20Sopenharmony_ci u8 req_duplex = bp->req_duplex; 69648c2ecf20Sopenharmony_ci u16 req_line_speed = bp->req_line_speed; 69658c2ecf20Sopenharmony_ci u32 advertising = bp->advertising; 69668c2ecf20Sopenharmony_ci int err = -EINVAL; 69678c2ecf20Sopenharmony_ci 69688c2ecf20Sopenharmony_ci spin_lock_bh(&bp->phy_lock); 69698c2ecf20Sopenharmony_ci 69708c2ecf20Sopenharmony_ci if (cmd->base.port != PORT_TP && cmd->base.port != PORT_FIBRE) 69718c2ecf20Sopenharmony_ci goto err_out_unlock; 69728c2ecf20Sopenharmony_ci 69738c2ecf20Sopenharmony_ci if (cmd->base.port != bp->phy_port && 69748c2ecf20Sopenharmony_ci !(bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP)) 69758c2ecf20Sopenharmony_ci goto err_out_unlock; 69768c2ecf20Sopenharmony_ci 69778c2ecf20Sopenharmony_ci /* If device is down, we can store the settings only if the user 69788c2ecf20Sopenharmony_ci * is setting the currently active port. 69798c2ecf20Sopenharmony_ci */ 69808c2ecf20Sopenharmony_ci if (!netif_running(dev) && cmd->base.port != bp->phy_port) 69818c2ecf20Sopenharmony_ci goto err_out_unlock; 69828c2ecf20Sopenharmony_ci 69838c2ecf20Sopenharmony_ci if (cmd->base.autoneg == AUTONEG_ENABLE) { 69848c2ecf20Sopenharmony_ci autoneg |= AUTONEG_SPEED; 69858c2ecf20Sopenharmony_ci 69868c2ecf20Sopenharmony_ci ethtool_convert_link_mode_to_legacy_u32( 69878c2ecf20Sopenharmony_ci &advertising, cmd->link_modes.advertising); 69888c2ecf20Sopenharmony_ci 69898c2ecf20Sopenharmony_ci if (cmd->base.port == PORT_TP) { 69908c2ecf20Sopenharmony_ci advertising &= ETHTOOL_ALL_COPPER_SPEED; 69918c2ecf20Sopenharmony_ci if (!advertising) 69928c2ecf20Sopenharmony_ci advertising = ETHTOOL_ALL_COPPER_SPEED; 69938c2ecf20Sopenharmony_ci } else { 69948c2ecf20Sopenharmony_ci advertising &= ETHTOOL_ALL_FIBRE_SPEED; 69958c2ecf20Sopenharmony_ci if (!advertising) 69968c2ecf20Sopenharmony_ci advertising = ETHTOOL_ALL_FIBRE_SPEED; 69978c2ecf20Sopenharmony_ci } 69988c2ecf20Sopenharmony_ci advertising |= ADVERTISED_Autoneg; 69998c2ecf20Sopenharmony_ci } 70008c2ecf20Sopenharmony_ci else { 70018c2ecf20Sopenharmony_ci u32 speed = cmd->base.speed; 70028c2ecf20Sopenharmony_ci 70038c2ecf20Sopenharmony_ci if (cmd->base.port == PORT_FIBRE) { 70048c2ecf20Sopenharmony_ci if ((speed != SPEED_1000 && 70058c2ecf20Sopenharmony_ci speed != SPEED_2500) || 70068c2ecf20Sopenharmony_ci (cmd->base.duplex != DUPLEX_FULL)) 70078c2ecf20Sopenharmony_ci goto err_out_unlock; 70088c2ecf20Sopenharmony_ci 70098c2ecf20Sopenharmony_ci if (speed == SPEED_2500 && 70108c2ecf20Sopenharmony_ci !(bp->phy_flags & BNX2_PHY_FLAG_2_5G_CAPABLE)) 70118c2ecf20Sopenharmony_ci goto err_out_unlock; 70128c2ecf20Sopenharmony_ci } else if (speed == SPEED_1000 || speed == SPEED_2500) 70138c2ecf20Sopenharmony_ci goto err_out_unlock; 70148c2ecf20Sopenharmony_ci 70158c2ecf20Sopenharmony_ci autoneg &= ~AUTONEG_SPEED; 70168c2ecf20Sopenharmony_ci req_line_speed = speed; 70178c2ecf20Sopenharmony_ci req_duplex = cmd->base.duplex; 70188c2ecf20Sopenharmony_ci advertising = 0; 70198c2ecf20Sopenharmony_ci } 70208c2ecf20Sopenharmony_ci 70218c2ecf20Sopenharmony_ci bp->autoneg = autoneg; 70228c2ecf20Sopenharmony_ci bp->advertising = advertising; 70238c2ecf20Sopenharmony_ci bp->req_line_speed = req_line_speed; 70248c2ecf20Sopenharmony_ci bp->req_duplex = req_duplex; 70258c2ecf20Sopenharmony_ci 70268c2ecf20Sopenharmony_ci err = 0; 70278c2ecf20Sopenharmony_ci /* If device is down, the new settings will be picked up when it is 70288c2ecf20Sopenharmony_ci * brought up. 70298c2ecf20Sopenharmony_ci */ 70308c2ecf20Sopenharmony_ci if (netif_running(dev)) 70318c2ecf20Sopenharmony_ci err = bnx2_setup_phy(bp, cmd->base.port); 70328c2ecf20Sopenharmony_ci 70338c2ecf20Sopenharmony_cierr_out_unlock: 70348c2ecf20Sopenharmony_ci spin_unlock_bh(&bp->phy_lock); 70358c2ecf20Sopenharmony_ci 70368c2ecf20Sopenharmony_ci return err; 70378c2ecf20Sopenharmony_ci} 70388c2ecf20Sopenharmony_ci 70398c2ecf20Sopenharmony_cistatic void 70408c2ecf20Sopenharmony_cibnx2_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) 70418c2ecf20Sopenharmony_ci{ 70428c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 70438c2ecf20Sopenharmony_ci 70448c2ecf20Sopenharmony_ci strlcpy(info->driver, DRV_MODULE_NAME, sizeof(info->driver)); 70458c2ecf20Sopenharmony_ci strlcpy(info->bus_info, pci_name(bp->pdev), sizeof(info->bus_info)); 70468c2ecf20Sopenharmony_ci strlcpy(info->fw_version, bp->fw_version, sizeof(info->fw_version)); 70478c2ecf20Sopenharmony_ci} 70488c2ecf20Sopenharmony_ci 70498c2ecf20Sopenharmony_ci#define BNX2_REGDUMP_LEN (32 * 1024) 70508c2ecf20Sopenharmony_ci 70518c2ecf20Sopenharmony_cistatic int 70528c2ecf20Sopenharmony_cibnx2_get_regs_len(struct net_device *dev) 70538c2ecf20Sopenharmony_ci{ 70548c2ecf20Sopenharmony_ci return BNX2_REGDUMP_LEN; 70558c2ecf20Sopenharmony_ci} 70568c2ecf20Sopenharmony_ci 70578c2ecf20Sopenharmony_cistatic void 70588c2ecf20Sopenharmony_cibnx2_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p) 70598c2ecf20Sopenharmony_ci{ 70608c2ecf20Sopenharmony_ci u32 *p = _p, i, offset; 70618c2ecf20Sopenharmony_ci u8 *orig_p = _p; 70628c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 70638c2ecf20Sopenharmony_ci static const u32 reg_boundaries[] = { 70648c2ecf20Sopenharmony_ci 0x0000, 0x0098, 0x0400, 0x045c, 70658c2ecf20Sopenharmony_ci 0x0800, 0x0880, 0x0c00, 0x0c10, 70668c2ecf20Sopenharmony_ci 0x0c30, 0x0d08, 0x1000, 0x101c, 70678c2ecf20Sopenharmony_ci 0x1040, 0x1048, 0x1080, 0x10a4, 70688c2ecf20Sopenharmony_ci 0x1400, 0x1490, 0x1498, 0x14f0, 70698c2ecf20Sopenharmony_ci 0x1500, 0x155c, 0x1580, 0x15dc, 70708c2ecf20Sopenharmony_ci 0x1600, 0x1658, 0x1680, 0x16d8, 70718c2ecf20Sopenharmony_ci 0x1800, 0x1820, 0x1840, 0x1854, 70728c2ecf20Sopenharmony_ci 0x1880, 0x1894, 0x1900, 0x1984, 70738c2ecf20Sopenharmony_ci 0x1c00, 0x1c0c, 0x1c40, 0x1c54, 70748c2ecf20Sopenharmony_ci 0x1c80, 0x1c94, 0x1d00, 0x1d84, 70758c2ecf20Sopenharmony_ci 0x2000, 0x2030, 0x23c0, 0x2400, 70768c2ecf20Sopenharmony_ci 0x2800, 0x2820, 0x2830, 0x2850, 70778c2ecf20Sopenharmony_ci 0x2b40, 0x2c10, 0x2fc0, 0x3058, 70788c2ecf20Sopenharmony_ci 0x3c00, 0x3c94, 0x4000, 0x4010, 70798c2ecf20Sopenharmony_ci 0x4080, 0x4090, 0x43c0, 0x4458, 70808c2ecf20Sopenharmony_ci 0x4c00, 0x4c18, 0x4c40, 0x4c54, 70818c2ecf20Sopenharmony_ci 0x4fc0, 0x5010, 0x53c0, 0x5444, 70828c2ecf20Sopenharmony_ci 0x5c00, 0x5c18, 0x5c80, 0x5c90, 70838c2ecf20Sopenharmony_ci 0x5fc0, 0x6000, 0x6400, 0x6428, 70848c2ecf20Sopenharmony_ci 0x6800, 0x6848, 0x684c, 0x6860, 70858c2ecf20Sopenharmony_ci 0x6888, 0x6910, 0x8000 70868c2ecf20Sopenharmony_ci }; 70878c2ecf20Sopenharmony_ci 70888c2ecf20Sopenharmony_ci regs->version = 0; 70898c2ecf20Sopenharmony_ci 70908c2ecf20Sopenharmony_ci memset(p, 0, BNX2_REGDUMP_LEN); 70918c2ecf20Sopenharmony_ci 70928c2ecf20Sopenharmony_ci if (!netif_running(bp->dev)) 70938c2ecf20Sopenharmony_ci return; 70948c2ecf20Sopenharmony_ci 70958c2ecf20Sopenharmony_ci i = 0; 70968c2ecf20Sopenharmony_ci offset = reg_boundaries[0]; 70978c2ecf20Sopenharmony_ci p += offset; 70988c2ecf20Sopenharmony_ci while (offset < BNX2_REGDUMP_LEN) { 70998c2ecf20Sopenharmony_ci *p++ = BNX2_RD(bp, offset); 71008c2ecf20Sopenharmony_ci offset += 4; 71018c2ecf20Sopenharmony_ci if (offset == reg_boundaries[i + 1]) { 71028c2ecf20Sopenharmony_ci offset = reg_boundaries[i + 2]; 71038c2ecf20Sopenharmony_ci p = (u32 *) (orig_p + offset); 71048c2ecf20Sopenharmony_ci i += 2; 71058c2ecf20Sopenharmony_ci } 71068c2ecf20Sopenharmony_ci } 71078c2ecf20Sopenharmony_ci} 71088c2ecf20Sopenharmony_ci 71098c2ecf20Sopenharmony_cistatic void 71108c2ecf20Sopenharmony_cibnx2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 71118c2ecf20Sopenharmony_ci{ 71128c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 71138c2ecf20Sopenharmony_ci 71148c2ecf20Sopenharmony_ci if (bp->flags & BNX2_FLAG_NO_WOL) { 71158c2ecf20Sopenharmony_ci wol->supported = 0; 71168c2ecf20Sopenharmony_ci wol->wolopts = 0; 71178c2ecf20Sopenharmony_ci } 71188c2ecf20Sopenharmony_ci else { 71198c2ecf20Sopenharmony_ci wol->supported = WAKE_MAGIC; 71208c2ecf20Sopenharmony_ci if (bp->wol) 71218c2ecf20Sopenharmony_ci wol->wolopts = WAKE_MAGIC; 71228c2ecf20Sopenharmony_ci else 71238c2ecf20Sopenharmony_ci wol->wolopts = 0; 71248c2ecf20Sopenharmony_ci } 71258c2ecf20Sopenharmony_ci memset(&wol->sopass, 0, sizeof(wol->sopass)); 71268c2ecf20Sopenharmony_ci} 71278c2ecf20Sopenharmony_ci 71288c2ecf20Sopenharmony_cistatic int 71298c2ecf20Sopenharmony_cibnx2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) 71308c2ecf20Sopenharmony_ci{ 71318c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 71328c2ecf20Sopenharmony_ci 71338c2ecf20Sopenharmony_ci if (wol->wolopts & ~WAKE_MAGIC) 71348c2ecf20Sopenharmony_ci return -EINVAL; 71358c2ecf20Sopenharmony_ci 71368c2ecf20Sopenharmony_ci if (wol->wolopts & WAKE_MAGIC) { 71378c2ecf20Sopenharmony_ci if (bp->flags & BNX2_FLAG_NO_WOL) 71388c2ecf20Sopenharmony_ci return -EINVAL; 71398c2ecf20Sopenharmony_ci 71408c2ecf20Sopenharmony_ci bp->wol = 1; 71418c2ecf20Sopenharmony_ci } 71428c2ecf20Sopenharmony_ci else { 71438c2ecf20Sopenharmony_ci bp->wol = 0; 71448c2ecf20Sopenharmony_ci } 71458c2ecf20Sopenharmony_ci 71468c2ecf20Sopenharmony_ci device_set_wakeup_enable(&bp->pdev->dev, bp->wol); 71478c2ecf20Sopenharmony_ci 71488c2ecf20Sopenharmony_ci return 0; 71498c2ecf20Sopenharmony_ci} 71508c2ecf20Sopenharmony_ci 71518c2ecf20Sopenharmony_cistatic int 71528c2ecf20Sopenharmony_cibnx2_nway_reset(struct net_device *dev) 71538c2ecf20Sopenharmony_ci{ 71548c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 71558c2ecf20Sopenharmony_ci u32 bmcr; 71568c2ecf20Sopenharmony_ci 71578c2ecf20Sopenharmony_ci if (!netif_running(dev)) 71588c2ecf20Sopenharmony_ci return -EAGAIN; 71598c2ecf20Sopenharmony_ci 71608c2ecf20Sopenharmony_ci if (!(bp->autoneg & AUTONEG_SPEED)) { 71618c2ecf20Sopenharmony_ci return -EINVAL; 71628c2ecf20Sopenharmony_ci } 71638c2ecf20Sopenharmony_ci 71648c2ecf20Sopenharmony_ci spin_lock_bh(&bp->phy_lock); 71658c2ecf20Sopenharmony_ci 71668c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) { 71678c2ecf20Sopenharmony_ci int rc; 71688c2ecf20Sopenharmony_ci 71698c2ecf20Sopenharmony_ci rc = bnx2_setup_remote_phy(bp, bp->phy_port); 71708c2ecf20Sopenharmony_ci spin_unlock_bh(&bp->phy_lock); 71718c2ecf20Sopenharmony_ci return rc; 71728c2ecf20Sopenharmony_ci } 71738c2ecf20Sopenharmony_ci 71748c2ecf20Sopenharmony_ci /* Force a link down visible on the other side */ 71758c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) { 71768c2ecf20Sopenharmony_ci bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK); 71778c2ecf20Sopenharmony_ci spin_unlock_bh(&bp->phy_lock); 71788c2ecf20Sopenharmony_ci 71798c2ecf20Sopenharmony_ci msleep(20); 71808c2ecf20Sopenharmony_ci 71818c2ecf20Sopenharmony_ci spin_lock_bh(&bp->phy_lock); 71828c2ecf20Sopenharmony_ci 71838c2ecf20Sopenharmony_ci bp->current_interval = BNX2_SERDES_AN_TIMEOUT; 71848c2ecf20Sopenharmony_ci bp->serdes_an_pending = 1; 71858c2ecf20Sopenharmony_ci mod_timer(&bp->timer, jiffies + bp->current_interval); 71868c2ecf20Sopenharmony_ci } 71878c2ecf20Sopenharmony_ci 71888c2ecf20Sopenharmony_ci bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); 71898c2ecf20Sopenharmony_ci bmcr &= ~BMCR_LOOPBACK; 71908c2ecf20Sopenharmony_ci bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART | BMCR_ANENABLE); 71918c2ecf20Sopenharmony_ci 71928c2ecf20Sopenharmony_ci spin_unlock_bh(&bp->phy_lock); 71938c2ecf20Sopenharmony_ci 71948c2ecf20Sopenharmony_ci return 0; 71958c2ecf20Sopenharmony_ci} 71968c2ecf20Sopenharmony_ci 71978c2ecf20Sopenharmony_cistatic u32 71988c2ecf20Sopenharmony_cibnx2_get_link(struct net_device *dev) 71998c2ecf20Sopenharmony_ci{ 72008c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 72018c2ecf20Sopenharmony_ci 72028c2ecf20Sopenharmony_ci return bp->link_up; 72038c2ecf20Sopenharmony_ci} 72048c2ecf20Sopenharmony_ci 72058c2ecf20Sopenharmony_cistatic int 72068c2ecf20Sopenharmony_cibnx2_get_eeprom_len(struct net_device *dev) 72078c2ecf20Sopenharmony_ci{ 72088c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 72098c2ecf20Sopenharmony_ci 72108c2ecf20Sopenharmony_ci if (!bp->flash_info) 72118c2ecf20Sopenharmony_ci return 0; 72128c2ecf20Sopenharmony_ci 72138c2ecf20Sopenharmony_ci return (int) bp->flash_size; 72148c2ecf20Sopenharmony_ci} 72158c2ecf20Sopenharmony_ci 72168c2ecf20Sopenharmony_cistatic int 72178c2ecf20Sopenharmony_cibnx2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, 72188c2ecf20Sopenharmony_ci u8 *eebuf) 72198c2ecf20Sopenharmony_ci{ 72208c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 72218c2ecf20Sopenharmony_ci int rc; 72228c2ecf20Sopenharmony_ci 72238c2ecf20Sopenharmony_ci /* parameters already validated in ethtool_get_eeprom */ 72248c2ecf20Sopenharmony_ci 72258c2ecf20Sopenharmony_ci rc = bnx2_nvram_read(bp, eeprom->offset, eebuf, eeprom->len); 72268c2ecf20Sopenharmony_ci 72278c2ecf20Sopenharmony_ci return rc; 72288c2ecf20Sopenharmony_ci} 72298c2ecf20Sopenharmony_ci 72308c2ecf20Sopenharmony_cistatic int 72318c2ecf20Sopenharmony_cibnx2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, 72328c2ecf20Sopenharmony_ci u8 *eebuf) 72338c2ecf20Sopenharmony_ci{ 72348c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 72358c2ecf20Sopenharmony_ci int rc; 72368c2ecf20Sopenharmony_ci 72378c2ecf20Sopenharmony_ci /* parameters already validated in ethtool_set_eeprom */ 72388c2ecf20Sopenharmony_ci 72398c2ecf20Sopenharmony_ci rc = bnx2_nvram_write(bp, eeprom->offset, eebuf, eeprom->len); 72408c2ecf20Sopenharmony_ci 72418c2ecf20Sopenharmony_ci return rc; 72428c2ecf20Sopenharmony_ci} 72438c2ecf20Sopenharmony_ci 72448c2ecf20Sopenharmony_cistatic int 72458c2ecf20Sopenharmony_cibnx2_get_coalesce(struct net_device *dev, struct ethtool_coalesce *coal) 72468c2ecf20Sopenharmony_ci{ 72478c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 72488c2ecf20Sopenharmony_ci 72498c2ecf20Sopenharmony_ci memset(coal, 0, sizeof(struct ethtool_coalesce)); 72508c2ecf20Sopenharmony_ci 72518c2ecf20Sopenharmony_ci coal->rx_coalesce_usecs = bp->rx_ticks; 72528c2ecf20Sopenharmony_ci coal->rx_max_coalesced_frames = bp->rx_quick_cons_trip; 72538c2ecf20Sopenharmony_ci coal->rx_coalesce_usecs_irq = bp->rx_ticks_int; 72548c2ecf20Sopenharmony_ci coal->rx_max_coalesced_frames_irq = bp->rx_quick_cons_trip_int; 72558c2ecf20Sopenharmony_ci 72568c2ecf20Sopenharmony_ci coal->tx_coalesce_usecs = bp->tx_ticks; 72578c2ecf20Sopenharmony_ci coal->tx_max_coalesced_frames = bp->tx_quick_cons_trip; 72588c2ecf20Sopenharmony_ci coal->tx_coalesce_usecs_irq = bp->tx_ticks_int; 72598c2ecf20Sopenharmony_ci coal->tx_max_coalesced_frames_irq = bp->tx_quick_cons_trip_int; 72608c2ecf20Sopenharmony_ci 72618c2ecf20Sopenharmony_ci coal->stats_block_coalesce_usecs = bp->stats_ticks; 72628c2ecf20Sopenharmony_ci 72638c2ecf20Sopenharmony_ci return 0; 72648c2ecf20Sopenharmony_ci} 72658c2ecf20Sopenharmony_ci 72668c2ecf20Sopenharmony_cistatic int 72678c2ecf20Sopenharmony_cibnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal) 72688c2ecf20Sopenharmony_ci{ 72698c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 72708c2ecf20Sopenharmony_ci 72718c2ecf20Sopenharmony_ci bp->rx_ticks = (u16) coal->rx_coalesce_usecs; 72728c2ecf20Sopenharmony_ci if (bp->rx_ticks > 0x3ff) bp->rx_ticks = 0x3ff; 72738c2ecf20Sopenharmony_ci 72748c2ecf20Sopenharmony_ci bp->rx_quick_cons_trip = (u16) coal->rx_max_coalesced_frames; 72758c2ecf20Sopenharmony_ci if (bp->rx_quick_cons_trip > 0xff) bp->rx_quick_cons_trip = 0xff; 72768c2ecf20Sopenharmony_ci 72778c2ecf20Sopenharmony_ci bp->rx_ticks_int = (u16) coal->rx_coalesce_usecs_irq; 72788c2ecf20Sopenharmony_ci if (bp->rx_ticks_int > 0x3ff) bp->rx_ticks_int = 0x3ff; 72798c2ecf20Sopenharmony_ci 72808c2ecf20Sopenharmony_ci bp->rx_quick_cons_trip_int = (u16) coal->rx_max_coalesced_frames_irq; 72818c2ecf20Sopenharmony_ci if (bp->rx_quick_cons_trip_int > 0xff) 72828c2ecf20Sopenharmony_ci bp->rx_quick_cons_trip_int = 0xff; 72838c2ecf20Sopenharmony_ci 72848c2ecf20Sopenharmony_ci bp->tx_ticks = (u16) coal->tx_coalesce_usecs; 72858c2ecf20Sopenharmony_ci if (bp->tx_ticks > 0x3ff) bp->tx_ticks = 0x3ff; 72868c2ecf20Sopenharmony_ci 72878c2ecf20Sopenharmony_ci bp->tx_quick_cons_trip = (u16) coal->tx_max_coalesced_frames; 72888c2ecf20Sopenharmony_ci if (bp->tx_quick_cons_trip > 0xff) bp->tx_quick_cons_trip = 0xff; 72898c2ecf20Sopenharmony_ci 72908c2ecf20Sopenharmony_ci bp->tx_ticks_int = (u16) coal->tx_coalesce_usecs_irq; 72918c2ecf20Sopenharmony_ci if (bp->tx_ticks_int > 0x3ff) bp->tx_ticks_int = 0x3ff; 72928c2ecf20Sopenharmony_ci 72938c2ecf20Sopenharmony_ci bp->tx_quick_cons_trip_int = (u16) coal->tx_max_coalesced_frames_irq; 72948c2ecf20Sopenharmony_ci if (bp->tx_quick_cons_trip_int > 0xff) bp->tx_quick_cons_trip_int = 72958c2ecf20Sopenharmony_ci 0xff; 72968c2ecf20Sopenharmony_ci 72978c2ecf20Sopenharmony_ci bp->stats_ticks = coal->stats_block_coalesce_usecs; 72988c2ecf20Sopenharmony_ci if (bp->flags & BNX2_FLAG_BROKEN_STATS) { 72998c2ecf20Sopenharmony_ci if (bp->stats_ticks != 0 && bp->stats_ticks != USEC_PER_SEC) 73008c2ecf20Sopenharmony_ci bp->stats_ticks = USEC_PER_SEC; 73018c2ecf20Sopenharmony_ci } 73028c2ecf20Sopenharmony_ci if (bp->stats_ticks > BNX2_HC_STATS_TICKS_HC_STAT_TICKS) 73038c2ecf20Sopenharmony_ci bp->stats_ticks = BNX2_HC_STATS_TICKS_HC_STAT_TICKS; 73048c2ecf20Sopenharmony_ci bp->stats_ticks &= BNX2_HC_STATS_TICKS_HC_STAT_TICKS; 73058c2ecf20Sopenharmony_ci 73068c2ecf20Sopenharmony_ci if (netif_running(bp->dev)) { 73078c2ecf20Sopenharmony_ci bnx2_netif_stop(bp, true); 73088c2ecf20Sopenharmony_ci bnx2_init_nic(bp, 0); 73098c2ecf20Sopenharmony_ci bnx2_netif_start(bp, true); 73108c2ecf20Sopenharmony_ci } 73118c2ecf20Sopenharmony_ci 73128c2ecf20Sopenharmony_ci return 0; 73138c2ecf20Sopenharmony_ci} 73148c2ecf20Sopenharmony_ci 73158c2ecf20Sopenharmony_cistatic void 73168c2ecf20Sopenharmony_cibnx2_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering) 73178c2ecf20Sopenharmony_ci{ 73188c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 73198c2ecf20Sopenharmony_ci 73208c2ecf20Sopenharmony_ci ering->rx_max_pending = BNX2_MAX_TOTAL_RX_DESC_CNT; 73218c2ecf20Sopenharmony_ci ering->rx_jumbo_max_pending = BNX2_MAX_TOTAL_RX_PG_DESC_CNT; 73228c2ecf20Sopenharmony_ci 73238c2ecf20Sopenharmony_ci ering->rx_pending = bp->rx_ring_size; 73248c2ecf20Sopenharmony_ci ering->rx_jumbo_pending = bp->rx_pg_ring_size; 73258c2ecf20Sopenharmony_ci 73268c2ecf20Sopenharmony_ci ering->tx_max_pending = BNX2_MAX_TX_DESC_CNT; 73278c2ecf20Sopenharmony_ci ering->tx_pending = bp->tx_ring_size; 73288c2ecf20Sopenharmony_ci} 73298c2ecf20Sopenharmony_ci 73308c2ecf20Sopenharmony_cistatic int 73318c2ecf20Sopenharmony_cibnx2_change_ring_size(struct bnx2 *bp, u32 rx, u32 tx, bool reset_irq) 73328c2ecf20Sopenharmony_ci{ 73338c2ecf20Sopenharmony_ci if (netif_running(bp->dev)) { 73348c2ecf20Sopenharmony_ci /* Reset will erase chipset stats; save them */ 73358c2ecf20Sopenharmony_ci bnx2_save_stats(bp); 73368c2ecf20Sopenharmony_ci 73378c2ecf20Sopenharmony_ci bnx2_netif_stop(bp, true); 73388c2ecf20Sopenharmony_ci bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET); 73398c2ecf20Sopenharmony_ci if (reset_irq) { 73408c2ecf20Sopenharmony_ci bnx2_free_irq(bp); 73418c2ecf20Sopenharmony_ci bnx2_del_napi(bp); 73428c2ecf20Sopenharmony_ci } else { 73438c2ecf20Sopenharmony_ci __bnx2_free_irq(bp); 73448c2ecf20Sopenharmony_ci } 73458c2ecf20Sopenharmony_ci bnx2_free_skbs(bp); 73468c2ecf20Sopenharmony_ci bnx2_free_mem(bp); 73478c2ecf20Sopenharmony_ci } 73488c2ecf20Sopenharmony_ci 73498c2ecf20Sopenharmony_ci bnx2_set_rx_ring_size(bp, rx); 73508c2ecf20Sopenharmony_ci bp->tx_ring_size = tx; 73518c2ecf20Sopenharmony_ci 73528c2ecf20Sopenharmony_ci if (netif_running(bp->dev)) { 73538c2ecf20Sopenharmony_ci int rc = 0; 73548c2ecf20Sopenharmony_ci 73558c2ecf20Sopenharmony_ci if (reset_irq) { 73568c2ecf20Sopenharmony_ci rc = bnx2_setup_int_mode(bp, disable_msi); 73578c2ecf20Sopenharmony_ci bnx2_init_napi(bp); 73588c2ecf20Sopenharmony_ci } 73598c2ecf20Sopenharmony_ci 73608c2ecf20Sopenharmony_ci if (!rc) 73618c2ecf20Sopenharmony_ci rc = bnx2_alloc_mem(bp); 73628c2ecf20Sopenharmony_ci 73638c2ecf20Sopenharmony_ci if (!rc) 73648c2ecf20Sopenharmony_ci rc = bnx2_request_irq(bp); 73658c2ecf20Sopenharmony_ci 73668c2ecf20Sopenharmony_ci if (!rc) 73678c2ecf20Sopenharmony_ci rc = bnx2_init_nic(bp, 0); 73688c2ecf20Sopenharmony_ci 73698c2ecf20Sopenharmony_ci if (rc) { 73708c2ecf20Sopenharmony_ci bnx2_napi_enable(bp); 73718c2ecf20Sopenharmony_ci dev_close(bp->dev); 73728c2ecf20Sopenharmony_ci return rc; 73738c2ecf20Sopenharmony_ci } 73748c2ecf20Sopenharmony_ci#ifdef BCM_CNIC 73758c2ecf20Sopenharmony_ci mutex_lock(&bp->cnic_lock); 73768c2ecf20Sopenharmony_ci /* Let cnic know about the new status block. */ 73778c2ecf20Sopenharmony_ci if (bp->cnic_eth_dev.drv_state & CNIC_DRV_STATE_REGD) 73788c2ecf20Sopenharmony_ci bnx2_setup_cnic_irq_info(bp); 73798c2ecf20Sopenharmony_ci mutex_unlock(&bp->cnic_lock); 73808c2ecf20Sopenharmony_ci#endif 73818c2ecf20Sopenharmony_ci bnx2_netif_start(bp, true); 73828c2ecf20Sopenharmony_ci } 73838c2ecf20Sopenharmony_ci return 0; 73848c2ecf20Sopenharmony_ci} 73858c2ecf20Sopenharmony_ci 73868c2ecf20Sopenharmony_cistatic int 73878c2ecf20Sopenharmony_cibnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering) 73888c2ecf20Sopenharmony_ci{ 73898c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 73908c2ecf20Sopenharmony_ci int rc; 73918c2ecf20Sopenharmony_ci 73928c2ecf20Sopenharmony_ci if ((ering->rx_pending > BNX2_MAX_TOTAL_RX_DESC_CNT) || 73938c2ecf20Sopenharmony_ci (ering->tx_pending > BNX2_MAX_TX_DESC_CNT) || 73948c2ecf20Sopenharmony_ci (ering->tx_pending <= MAX_SKB_FRAGS)) { 73958c2ecf20Sopenharmony_ci 73968c2ecf20Sopenharmony_ci return -EINVAL; 73978c2ecf20Sopenharmony_ci } 73988c2ecf20Sopenharmony_ci rc = bnx2_change_ring_size(bp, ering->rx_pending, ering->tx_pending, 73998c2ecf20Sopenharmony_ci false); 74008c2ecf20Sopenharmony_ci return rc; 74018c2ecf20Sopenharmony_ci} 74028c2ecf20Sopenharmony_ci 74038c2ecf20Sopenharmony_cistatic void 74048c2ecf20Sopenharmony_cibnx2_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause) 74058c2ecf20Sopenharmony_ci{ 74068c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 74078c2ecf20Sopenharmony_ci 74088c2ecf20Sopenharmony_ci epause->autoneg = ((bp->autoneg & AUTONEG_FLOW_CTRL) != 0); 74098c2ecf20Sopenharmony_ci epause->rx_pause = ((bp->flow_ctrl & FLOW_CTRL_RX) != 0); 74108c2ecf20Sopenharmony_ci epause->tx_pause = ((bp->flow_ctrl & FLOW_CTRL_TX) != 0); 74118c2ecf20Sopenharmony_ci} 74128c2ecf20Sopenharmony_ci 74138c2ecf20Sopenharmony_cistatic int 74148c2ecf20Sopenharmony_cibnx2_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause) 74158c2ecf20Sopenharmony_ci{ 74168c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 74178c2ecf20Sopenharmony_ci 74188c2ecf20Sopenharmony_ci bp->req_flow_ctrl = 0; 74198c2ecf20Sopenharmony_ci if (epause->rx_pause) 74208c2ecf20Sopenharmony_ci bp->req_flow_ctrl |= FLOW_CTRL_RX; 74218c2ecf20Sopenharmony_ci if (epause->tx_pause) 74228c2ecf20Sopenharmony_ci bp->req_flow_ctrl |= FLOW_CTRL_TX; 74238c2ecf20Sopenharmony_ci 74248c2ecf20Sopenharmony_ci if (epause->autoneg) { 74258c2ecf20Sopenharmony_ci bp->autoneg |= AUTONEG_FLOW_CTRL; 74268c2ecf20Sopenharmony_ci } 74278c2ecf20Sopenharmony_ci else { 74288c2ecf20Sopenharmony_ci bp->autoneg &= ~AUTONEG_FLOW_CTRL; 74298c2ecf20Sopenharmony_ci } 74308c2ecf20Sopenharmony_ci 74318c2ecf20Sopenharmony_ci if (netif_running(dev)) { 74328c2ecf20Sopenharmony_ci spin_lock_bh(&bp->phy_lock); 74338c2ecf20Sopenharmony_ci bnx2_setup_phy(bp, bp->phy_port); 74348c2ecf20Sopenharmony_ci spin_unlock_bh(&bp->phy_lock); 74358c2ecf20Sopenharmony_ci } 74368c2ecf20Sopenharmony_ci 74378c2ecf20Sopenharmony_ci return 0; 74388c2ecf20Sopenharmony_ci} 74398c2ecf20Sopenharmony_ci 74408c2ecf20Sopenharmony_cistatic struct { 74418c2ecf20Sopenharmony_ci char string[ETH_GSTRING_LEN]; 74428c2ecf20Sopenharmony_ci} bnx2_stats_str_arr[] = { 74438c2ecf20Sopenharmony_ci { "rx_bytes" }, 74448c2ecf20Sopenharmony_ci { "rx_error_bytes" }, 74458c2ecf20Sopenharmony_ci { "tx_bytes" }, 74468c2ecf20Sopenharmony_ci { "tx_error_bytes" }, 74478c2ecf20Sopenharmony_ci { "rx_ucast_packets" }, 74488c2ecf20Sopenharmony_ci { "rx_mcast_packets" }, 74498c2ecf20Sopenharmony_ci { "rx_bcast_packets" }, 74508c2ecf20Sopenharmony_ci { "tx_ucast_packets" }, 74518c2ecf20Sopenharmony_ci { "tx_mcast_packets" }, 74528c2ecf20Sopenharmony_ci { "tx_bcast_packets" }, 74538c2ecf20Sopenharmony_ci { "tx_mac_errors" }, 74548c2ecf20Sopenharmony_ci { "tx_carrier_errors" }, 74558c2ecf20Sopenharmony_ci { "rx_crc_errors" }, 74568c2ecf20Sopenharmony_ci { "rx_align_errors" }, 74578c2ecf20Sopenharmony_ci { "tx_single_collisions" }, 74588c2ecf20Sopenharmony_ci { "tx_multi_collisions" }, 74598c2ecf20Sopenharmony_ci { "tx_deferred" }, 74608c2ecf20Sopenharmony_ci { "tx_excess_collisions" }, 74618c2ecf20Sopenharmony_ci { "tx_late_collisions" }, 74628c2ecf20Sopenharmony_ci { "tx_total_collisions" }, 74638c2ecf20Sopenharmony_ci { "rx_fragments" }, 74648c2ecf20Sopenharmony_ci { "rx_jabbers" }, 74658c2ecf20Sopenharmony_ci { "rx_undersize_packets" }, 74668c2ecf20Sopenharmony_ci { "rx_oversize_packets" }, 74678c2ecf20Sopenharmony_ci { "rx_64_byte_packets" }, 74688c2ecf20Sopenharmony_ci { "rx_65_to_127_byte_packets" }, 74698c2ecf20Sopenharmony_ci { "rx_128_to_255_byte_packets" }, 74708c2ecf20Sopenharmony_ci { "rx_256_to_511_byte_packets" }, 74718c2ecf20Sopenharmony_ci { "rx_512_to_1023_byte_packets" }, 74728c2ecf20Sopenharmony_ci { "rx_1024_to_1522_byte_packets" }, 74738c2ecf20Sopenharmony_ci { "rx_1523_to_9022_byte_packets" }, 74748c2ecf20Sopenharmony_ci { "tx_64_byte_packets" }, 74758c2ecf20Sopenharmony_ci { "tx_65_to_127_byte_packets" }, 74768c2ecf20Sopenharmony_ci { "tx_128_to_255_byte_packets" }, 74778c2ecf20Sopenharmony_ci { "tx_256_to_511_byte_packets" }, 74788c2ecf20Sopenharmony_ci { "tx_512_to_1023_byte_packets" }, 74798c2ecf20Sopenharmony_ci { "tx_1024_to_1522_byte_packets" }, 74808c2ecf20Sopenharmony_ci { "tx_1523_to_9022_byte_packets" }, 74818c2ecf20Sopenharmony_ci { "rx_xon_frames" }, 74828c2ecf20Sopenharmony_ci { "rx_xoff_frames" }, 74838c2ecf20Sopenharmony_ci { "tx_xon_frames" }, 74848c2ecf20Sopenharmony_ci { "tx_xoff_frames" }, 74858c2ecf20Sopenharmony_ci { "rx_mac_ctrl_frames" }, 74868c2ecf20Sopenharmony_ci { "rx_filtered_packets" }, 74878c2ecf20Sopenharmony_ci { "rx_ftq_discards" }, 74888c2ecf20Sopenharmony_ci { "rx_discards" }, 74898c2ecf20Sopenharmony_ci { "rx_fw_discards" }, 74908c2ecf20Sopenharmony_ci}; 74918c2ecf20Sopenharmony_ci 74928c2ecf20Sopenharmony_ci#define BNX2_NUM_STATS ARRAY_SIZE(bnx2_stats_str_arr) 74938c2ecf20Sopenharmony_ci 74948c2ecf20Sopenharmony_ci#define STATS_OFFSET32(offset_name) (offsetof(struct statistics_block, offset_name) / 4) 74958c2ecf20Sopenharmony_ci 74968c2ecf20Sopenharmony_cistatic const unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = { 74978c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_IfHCInOctets_hi), 74988c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_IfHCInBadOctets_hi), 74998c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_IfHCOutOctets_hi), 75008c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_IfHCOutBadOctets_hi), 75018c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_IfHCInUcastPkts_hi), 75028c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_IfHCInMulticastPkts_hi), 75038c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_IfHCInBroadcastPkts_hi), 75048c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_IfHCOutUcastPkts_hi), 75058c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_IfHCOutMulticastPkts_hi), 75068c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_IfHCOutBroadcastPkts_hi), 75078c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_emac_tx_stat_dot3statsinternalmactransmiterrors), 75088c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_Dot3StatsCarrierSenseErrors), 75098c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_Dot3StatsFCSErrors), 75108c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_Dot3StatsAlignmentErrors), 75118c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_Dot3StatsSingleCollisionFrames), 75128c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_Dot3StatsMultipleCollisionFrames), 75138c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_Dot3StatsDeferredTransmissions), 75148c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_Dot3StatsExcessiveCollisions), 75158c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_Dot3StatsLateCollisions), 75168c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_EtherStatsCollisions), 75178c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_EtherStatsFragments), 75188c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_EtherStatsJabbers), 75198c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_EtherStatsUndersizePkts), 75208c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_EtherStatsOverrsizePkts), 75218c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_EtherStatsPktsRx64Octets), 75228c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_EtherStatsPktsRx65Octetsto127Octets), 75238c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_EtherStatsPktsRx128Octetsto255Octets), 75248c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_EtherStatsPktsRx256Octetsto511Octets), 75258c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_EtherStatsPktsRx512Octetsto1023Octets), 75268c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_EtherStatsPktsRx1024Octetsto1522Octets), 75278c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_EtherStatsPktsRx1523Octetsto9022Octets), 75288c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_EtherStatsPktsTx64Octets), 75298c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_EtherStatsPktsTx65Octetsto127Octets), 75308c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_EtherStatsPktsTx128Octetsto255Octets), 75318c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_EtherStatsPktsTx256Octetsto511Octets), 75328c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_EtherStatsPktsTx512Octetsto1023Octets), 75338c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_EtherStatsPktsTx1024Octetsto1522Octets), 75348c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_EtherStatsPktsTx1523Octetsto9022Octets), 75358c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_XonPauseFramesReceived), 75368c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_XoffPauseFramesReceived), 75378c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_OutXonSent), 75388c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_OutXoffSent), 75398c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_MacControlFramesReceived), 75408c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_IfInFramesL2FilterDiscards), 75418c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_IfInFTQDiscards), 75428c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_IfInMBUFDiscards), 75438c2ecf20Sopenharmony_ci STATS_OFFSET32(stat_FwRxDrop), 75448c2ecf20Sopenharmony_ci}; 75458c2ecf20Sopenharmony_ci 75468c2ecf20Sopenharmony_ci/* stat_IfHCInBadOctets and stat_Dot3StatsCarrierSenseErrors are 75478c2ecf20Sopenharmony_ci * skipped because of errata. 75488c2ecf20Sopenharmony_ci */ 75498c2ecf20Sopenharmony_cistatic u8 bnx2_5706_stats_len_arr[BNX2_NUM_STATS] = { 75508c2ecf20Sopenharmony_ci 8,0,8,8,8,8,8,8,8,8, 75518c2ecf20Sopenharmony_ci 4,0,4,4,4,4,4,4,4,4, 75528c2ecf20Sopenharmony_ci 4,4,4,4,4,4,4,4,4,4, 75538c2ecf20Sopenharmony_ci 4,4,4,4,4,4,4,4,4,4, 75548c2ecf20Sopenharmony_ci 4,4,4,4,4,4,4, 75558c2ecf20Sopenharmony_ci}; 75568c2ecf20Sopenharmony_ci 75578c2ecf20Sopenharmony_cistatic u8 bnx2_5708_stats_len_arr[BNX2_NUM_STATS] = { 75588c2ecf20Sopenharmony_ci 8,0,8,8,8,8,8,8,8,8, 75598c2ecf20Sopenharmony_ci 4,4,4,4,4,4,4,4,4,4, 75608c2ecf20Sopenharmony_ci 4,4,4,4,4,4,4,4,4,4, 75618c2ecf20Sopenharmony_ci 4,4,4,4,4,4,4,4,4,4, 75628c2ecf20Sopenharmony_ci 4,4,4,4,4,4,4, 75638c2ecf20Sopenharmony_ci}; 75648c2ecf20Sopenharmony_ci 75658c2ecf20Sopenharmony_ci#define BNX2_NUM_TESTS 6 75668c2ecf20Sopenharmony_ci 75678c2ecf20Sopenharmony_cistatic struct { 75688c2ecf20Sopenharmony_ci char string[ETH_GSTRING_LEN]; 75698c2ecf20Sopenharmony_ci} bnx2_tests_str_arr[BNX2_NUM_TESTS] = { 75708c2ecf20Sopenharmony_ci { "register_test (offline)" }, 75718c2ecf20Sopenharmony_ci { "memory_test (offline)" }, 75728c2ecf20Sopenharmony_ci { "loopback_test (offline)" }, 75738c2ecf20Sopenharmony_ci { "nvram_test (online)" }, 75748c2ecf20Sopenharmony_ci { "interrupt_test (online)" }, 75758c2ecf20Sopenharmony_ci { "link_test (online)" }, 75768c2ecf20Sopenharmony_ci}; 75778c2ecf20Sopenharmony_ci 75788c2ecf20Sopenharmony_cistatic int 75798c2ecf20Sopenharmony_cibnx2_get_sset_count(struct net_device *dev, int sset) 75808c2ecf20Sopenharmony_ci{ 75818c2ecf20Sopenharmony_ci switch (sset) { 75828c2ecf20Sopenharmony_ci case ETH_SS_TEST: 75838c2ecf20Sopenharmony_ci return BNX2_NUM_TESTS; 75848c2ecf20Sopenharmony_ci case ETH_SS_STATS: 75858c2ecf20Sopenharmony_ci return BNX2_NUM_STATS; 75868c2ecf20Sopenharmony_ci default: 75878c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 75888c2ecf20Sopenharmony_ci } 75898c2ecf20Sopenharmony_ci} 75908c2ecf20Sopenharmony_ci 75918c2ecf20Sopenharmony_cistatic void 75928c2ecf20Sopenharmony_cibnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf) 75938c2ecf20Sopenharmony_ci{ 75948c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 75958c2ecf20Sopenharmony_ci 75968c2ecf20Sopenharmony_ci memset(buf, 0, sizeof(u64) * BNX2_NUM_TESTS); 75978c2ecf20Sopenharmony_ci if (etest->flags & ETH_TEST_FL_OFFLINE) { 75988c2ecf20Sopenharmony_ci int i; 75998c2ecf20Sopenharmony_ci 76008c2ecf20Sopenharmony_ci bnx2_netif_stop(bp, true); 76018c2ecf20Sopenharmony_ci bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_DIAG); 76028c2ecf20Sopenharmony_ci bnx2_free_skbs(bp); 76038c2ecf20Sopenharmony_ci 76048c2ecf20Sopenharmony_ci if (bnx2_test_registers(bp) != 0) { 76058c2ecf20Sopenharmony_ci buf[0] = 1; 76068c2ecf20Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 76078c2ecf20Sopenharmony_ci } 76088c2ecf20Sopenharmony_ci if (bnx2_test_memory(bp) != 0) { 76098c2ecf20Sopenharmony_ci buf[1] = 1; 76108c2ecf20Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 76118c2ecf20Sopenharmony_ci } 76128c2ecf20Sopenharmony_ci if ((buf[2] = bnx2_test_loopback(bp)) != 0) 76138c2ecf20Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 76148c2ecf20Sopenharmony_ci 76158c2ecf20Sopenharmony_ci if (!netif_running(bp->dev)) 76168c2ecf20Sopenharmony_ci bnx2_shutdown_chip(bp); 76178c2ecf20Sopenharmony_ci else { 76188c2ecf20Sopenharmony_ci bnx2_init_nic(bp, 1); 76198c2ecf20Sopenharmony_ci bnx2_netif_start(bp, true); 76208c2ecf20Sopenharmony_ci } 76218c2ecf20Sopenharmony_ci 76228c2ecf20Sopenharmony_ci /* wait for link up */ 76238c2ecf20Sopenharmony_ci for (i = 0; i < 7; i++) { 76248c2ecf20Sopenharmony_ci if (bp->link_up) 76258c2ecf20Sopenharmony_ci break; 76268c2ecf20Sopenharmony_ci msleep_interruptible(1000); 76278c2ecf20Sopenharmony_ci } 76288c2ecf20Sopenharmony_ci } 76298c2ecf20Sopenharmony_ci 76308c2ecf20Sopenharmony_ci if (bnx2_test_nvram(bp) != 0) { 76318c2ecf20Sopenharmony_ci buf[3] = 1; 76328c2ecf20Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 76338c2ecf20Sopenharmony_ci } 76348c2ecf20Sopenharmony_ci if (bnx2_test_intr(bp) != 0) { 76358c2ecf20Sopenharmony_ci buf[4] = 1; 76368c2ecf20Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 76378c2ecf20Sopenharmony_ci } 76388c2ecf20Sopenharmony_ci 76398c2ecf20Sopenharmony_ci if (bnx2_test_link(bp) != 0) { 76408c2ecf20Sopenharmony_ci buf[5] = 1; 76418c2ecf20Sopenharmony_ci etest->flags |= ETH_TEST_FL_FAILED; 76428c2ecf20Sopenharmony_ci 76438c2ecf20Sopenharmony_ci } 76448c2ecf20Sopenharmony_ci} 76458c2ecf20Sopenharmony_ci 76468c2ecf20Sopenharmony_cistatic void 76478c2ecf20Sopenharmony_cibnx2_get_strings(struct net_device *dev, u32 stringset, u8 *buf) 76488c2ecf20Sopenharmony_ci{ 76498c2ecf20Sopenharmony_ci switch (stringset) { 76508c2ecf20Sopenharmony_ci case ETH_SS_STATS: 76518c2ecf20Sopenharmony_ci memcpy(buf, bnx2_stats_str_arr, 76528c2ecf20Sopenharmony_ci sizeof(bnx2_stats_str_arr)); 76538c2ecf20Sopenharmony_ci break; 76548c2ecf20Sopenharmony_ci case ETH_SS_TEST: 76558c2ecf20Sopenharmony_ci memcpy(buf, bnx2_tests_str_arr, 76568c2ecf20Sopenharmony_ci sizeof(bnx2_tests_str_arr)); 76578c2ecf20Sopenharmony_ci break; 76588c2ecf20Sopenharmony_ci } 76598c2ecf20Sopenharmony_ci} 76608c2ecf20Sopenharmony_ci 76618c2ecf20Sopenharmony_cistatic void 76628c2ecf20Sopenharmony_cibnx2_get_ethtool_stats(struct net_device *dev, 76638c2ecf20Sopenharmony_ci struct ethtool_stats *stats, u64 *buf) 76648c2ecf20Sopenharmony_ci{ 76658c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 76668c2ecf20Sopenharmony_ci int i; 76678c2ecf20Sopenharmony_ci u32 *hw_stats = (u32 *) bp->stats_blk; 76688c2ecf20Sopenharmony_ci u32 *temp_stats = (u32 *) bp->temp_stats_blk; 76698c2ecf20Sopenharmony_ci u8 *stats_len_arr = NULL; 76708c2ecf20Sopenharmony_ci 76718c2ecf20Sopenharmony_ci if (!hw_stats) { 76728c2ecf20Sopenharmony_ci memset(buf, 0, sizeof(u64) * BNX2_NUM_STATS); 76738c2ecf20Sopenharmony_ci return; 76748c2ecf20Sopenharmony_ci } 76758c2ecf20Sopenharmony_ci 76768c2ecf20Sopenharmony_ci if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) || 76778c2ecf20Sopenharmony_ci (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1) || 76788c2ecf20Sopenharmony_ci (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A2) || 76798c2ecf20Sopenharmony_ci (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_A0)) 76808c2ecf20Sopenharmony_ci stats_len_arr = bnx2_5706_stats_len_arr; 76818c2ecf20Sopenharmony_ci else 76828c2ecf20Sopenharmony_ci stats_len_arr = bnx2_5708_stats_len_arr; 76838c2ecf20Sopenharmony_ci 76848c2ecf20Sopenharmony_ci for (i = 0; i < BNX2_NUM_STATS; i++) { 76858c2ecf20Sopenharmony_ci unsigned long offset; 76868c2ecf20Sopenharmony_ci 76878c2ecf20Sopenharmony_ci if (stats_len_arr[i] == 0) { 76888c2ecf20Sopenharmony_ci /* skip this counter */ 76898c2ecf20Sopenharmony_ci buf[i] = 0; 76908c2ecf20Sopenharmony_ci continue; 76918c2ecf20Sopenharmony_ci } 76928c2ecf20Sopenharmony_ci 76938c2ecf20Sopenharmony_ci offset = bnx2_stats_offset_arr[i]; 76948c2ecf20Sopenharmony_ci if (stats_len_arr[i] == 4) { 76958c2ecf20Sopenharmony_ci /* 4-byte counter */ 76968c2ecf20Sopenharmony_ci buf[i] = (u64) *(hw_stats + offset) + 76978c2ecf20Sopenharmony_ci *(temp_stats + offset); 76988c2ecf20Sopenharmony_ci continue; 76998c2ecf20Sopenharmony_ci } 77008c2ecf20Sopenharmony_ci /* 8-byte counter */ 77018c2ecf20Sopenharmony_ci buf[i] = (((u64) *(hw_stats + offset)) << 32) + 77028c2ecf20Sopenharmony_ci *(hw_stats + offset + 1) + 77038c2ecf20Sopenharmony_ci (((u64) *(temp_stats + offset)) << 32) + 77048c2ecf20Sopenharmony_ci *(temp_stats + offset + 1); 77058c2ecf20Sopenharmony_ci } 77068c2ecf20Sopenharmony_ci} 77078c2ecf20Sopenharmony_ci 77088c2ecf20Sopenharmony_cistatic int 77098c2ecf20Sopenharmony_cibnx2_set_phys_id(struct net_device *dev, enum ethtool_phys_id_state state) 77108c2ecf20Sopenharmony_ci{ 77118c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 77128c2ecf20Sopenharmony_ci 77138c2ecf20Sopenharmony_ci switch (state) { 77148c2ecf20Sopenharmony_ci case ETHTOOL_ID_ACTIVE: 77158c2ecf20Sopenharmony_ci bp->leds_save = BNX2_RD(bp, BNX2_MISC_CFG); 77168c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_MISC_CFG, BNX2_MISC_CFG_LEDMODE_MAC); 77178c2ecf20Sopenharmony_ci return 1; /* cycle on/off once per second */ 77188c2ecf20Sopenharmony_ci 77198c2ecf20Sopenharmony_ci case ETHTOOL_ID_ON: 77208c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE | 77218c2ecf20Sopenharmony_ci BNX2_EMAC_LED_1000MB_OVERRIDE | 77228c2ecf20Sopenharmony_ci BNX2_EMAC_LED_100MB_OVERRIDE | 77238c2ecf20Sopenharmony_ci BNX2_EMAC_LED_10MB_OVERRIDE | 77248c2ecf20Sopenharmony_ci BNX2_EMAC_LED_TRAFFIC_OVERRIDE | 77258c2ecf20Sopenharmony_ci BNX2_EMAC_LED_TRAFFIC); 77268c2ecf20Sopenharmony_ci break; 77278c2ecf20Sopenharmony_ci 77288c2ecf20Sopenharmony_ci case ETHTOOL_ID_OFF: 77298c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE); 77308c2ecf20Sopenharmony_ci break; 77318c2ecf20Sopenharmony_ci 77328c2ecf20Sopenharmony_ci case ETHTOOL_ID_INACTIVE: 77338c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_EMAC_LED, 0); 77348c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_MISC_CFG, bp->leds_save); 77358c2ecf20Sopenharmony_ci break; 77368c2ecf20Sopenharmony_ci } 77378c2ecf20Sopenharmony_ci 77388c2ecf20Sopenharmony_ci return 0; 77398c2ecf20Sopenharmony_ci} 77408c2ecf20Sopenharmony_ci 77418c2ecf20Sopenharmony_cistatic int 77428c2ecf20Sopenharmony_cibnx2_set_features(struct net_device *dev, netdev_features_t features) 77438c2ecf20Sopenharmony_ci{ 77448c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 77458c2ecf20Sopenharmony_ci 77468c2ecf20Sopenharmony_ci /* TSO with VLAN tag won't work with current firmware */ 77478c2ecf20Sopenharmony_ci if (features & NETIF_F_HW_VLAN_CTAG_TX) 77488c2ecf20Sopenharmony_ci dev->vlan_features |= (dev->hw_features & NETIF_F_ALL_TSO); 77498c2ecf20Sopenharmony_ci else 77508c2ecf20Sopenharmony_ci dev->vlan_features &= ~NETIF_F_ALL_TSO; 77518c2ecf20Sopenharmony_ci 77528c2ecf20Sopenharmony_ci if ((!!(features & NETIF_F_HW_VLAN_CTAG_RX) != 77538c2ecf20Sopenharmony_ci !!(bp->rx_mode & BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG)) && 77548c2ecf20Sopenharmony_ci netif_running(dev)) { 77558c2ecf20Sopenharmony_ci bnx2_netif_stop(bp, false); 77568c2ecf20Sopenharmony_ci dev->features = features; 77578c2ecf20Sopenharmony_ci bnx2_set_rx_mode(dev); 77588c2ecf20Sopenharmony_ci bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_KEEP_VLAN_UPDATE, 0, 1); 77598c2ecf20Sopenharmony_ci bnx2_netif_start(bp, false); 77608c2ecf20Sopenharmony_ci return 1; 77618c2ecf20Sopenharmony_ci } 77628c2ecf20Sopenharmony_ci 77638c2ecf20Sopenharmony_ci return 0; 77648c2ecf20Sopenharmony_ci} 77658c2ecf20Sopenharmony_ci 77668c2ecf20Sopenharmony_cistatic void bnx2_get_channels(struct net_device *dev, 77678c2ecf20Sopenharmony_ci struct ethtool_channels *channels) 77688c2ecf20Sopenharmony_ci{ 77698c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 77708c2ecf20Sopenharmony_ci u32 max_rx_rings = 1; 77718c2ecf20Sopenharmony_ci u32 max_tx_rings = 1; 77728c2ecf20Sopenharmony_ci 77738c2ecf20Sopenharmony_ci if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !disable_msi) { 77748c2ecf20Sopenharmony_ci max_rx_rings = RX_MAX_RINGS; 77758c2ecf20Sopenharmony_ci max_tx_rings = TX_MAX_RINGS; 77768c2ecf20Sopenharmony_ci } 77778c2ecf20Sopenharmony_ci 77788c2ecf20Sopenharmony_ci channels->max_rx = max_rx_rings; 77798c2ecf20Sopenharmony_ci channels->max_tx = max_tx_rings; 77808c2ecf20Sopenharmony_ci channels->max_other = 0; 77818c2ecf20Sopenharmony_ci channels->max_combined = 0; 77828c2ecf20Sopenharmony_ci channels->rx_count = bp->num_rx_rings; 77838c2ecf20Sopenharmony_ci channels->tx_count = bp->num_tx_rings; 77848c2ecf20Sopenharmony_ci channels->other_count = 0; 77858c2ecf20Sopenharmony_ci channels->combined_count = 0; 77868c2ecf20Sopenharmony_ci} 77878c2ecf20Sopenharmony_ci 77888c2ecf20Sopenharmony_cistatic int bnx2_set_channels(struct net_device *dev, 77898c2ecf20Sopenharmony_ci struct ethtool_channels *channels) 77908c2ecf20Sopenharmony_ci{ 77918c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 77928c2ecf20Sopenharmony_ci u32 max_rx_rings = 1; 77938c2ecf20Sopenharmony_ci u32 max_tx_rings = 1; 77948c2ecf20Sopenharmony_ci int rc = 0; 77958c2ecf20Sopenharmony_ci 77968c2ecf20Sopenharmony_ci if ((bp->flags & BNX2_FLAG_MSIX_CAP) && !disable_msi) { 77978c2ecf20Sopenharmony_ci max_rx_rings = RX_MAX_RINGS; 77988c2ecf20Sopenharmony_ci max_tx_rings = TX_MAX_RINGS; 77998c2ecf20Sopenharmony_ci } 78008c2ecf20Sopenharmony_ci if (channels->rx_count > max_rx_rings || 78018c2ecf20Sopenharmony_ci channels->tx_count > max_tx_rings) 78028c2ecf20Sopenharmony_ci return -EINVAL; 78038c2ecf20Sopenharmony_ci 78048c2ecf20Sopenharmony_ci bp->num_req_rx_rings = channels->rx_count; 78058c2ecf20Sopenharmony_ci bp->num_req_tx_rings = channels->tx_count; 78068c2ecf20Sopenharmony_ci 78078c2ecf20Sopenharmony_ci if (netif_running(dev)) 78088c2ecf20Sopenharmony_ci rc = bnx2_change_ring_size(bp, bp->rx_ring_size, 78098c2ecf20Sopenharmony_ci bp->tx_ring_size, true); 78108c2ecf20Sopenharmony_ci 78118c2ecf20Sopenharmony_ci return rc; 78128c2ecf20Sopenharmony_ci} 78138c2ecf20Sopenharmony_ci 78148c2ecf20Sopenharmony_cistatic const struct ethtool_ops bnx2_ethtool_ops = { 78158c2ecf20Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_USECS | 78168c2ecf20Sopenharmony_ci ETHTOOL_COALESCE_MAX_FRAMES | 78178c2ecf20Sopenharmony_ci ETHTOOL_COALESCE_USECS_IRQ | 78188c2ecf20Sopenharmony_ci ETHTOOL_COALESCE_MAX_FRAMES_IRQ | 78198c2ecf20Sopenharmony_ci ETHTOOL_COALESCE_STATS_BLOCK_USECS, 78208c2ecf20Sopenharmony_ci .get_drvinfo = bnx2_get_drvinfo, 78218c2ecf20Sopenharmony_ci .get_regs_len = bnx2_get_regs_len, 78228c2ecf20Sopenharmony_ci .get_regs = bnx2_get_regs, 78238c2ecf20Sopenharmony_ci .get_wol = bnx2_get_wol, 78248c2ecf20Sopenharmony_ci .set_wol = bnx2_set_wol, 78258c2ecf20Sopenharmony_ci .nway_reset = bnx2_nway_reset, 78268c2ecf20Sopenharmony_ci .get_link = bnx2_get_link, 78278c2ecf20Sopenharmony_ci .get_eeprom_len = bnx2_get_eeprom_len, 78288c2ecf20Sopenharmony_ci .get_eeprom = bnx2_get_eeprom, 78298c2ecf20Sopenharmony_ci .set_eeprom = bnx2_set_eeprom, 78308c2ecf20Sopenharmony_ci .get_coalesce = bnx2_get_coalesce, 78318c2ecf20Sopenharmony_ci .set_coalesce = bnx2_set_coalesce, 78328c2ecf20Sopenharmony_ci .get_ringparam = bnx2_get_ringparam, 78338c2ecf20Sopenharmony_ci .set_ringparam = bnx2_set_ringparam, 78348c2ecf20Sopenharmony_ci .get_pauseparam = bnx2_get_pauseparam, 78358c2ecf20Sopenharmony_ci .set_pauseparam = bnx2_set_pauseparam, 78368c2ecf20Sopenharmony_ci .self_test = bnx2_self_test, 78378c2ecf20Sopenharmony_ci .get_strings = bnx2_get_strings, 78388c2ecf20Sopenharmony_ci .set_phys_id = bnx2_set_phys_id, 78398c2ecf20Sopenharmony_ci .get_ethtool_stats = bnx2_get_ethtool_stats, 78408c2ecf20Sopenharmony_ci .get_sset_count = bnx2_get_sset_count, 78418c2ecf20Sopenharmony_ci .get_channels = bnx2_get_channels, 78428c2ecf20Sopenharmony_ci .set_channels = bnx2_set_channels, 78438c2ecf20Sopenharmony_ci .get_link_ksettings = bnx2_get_link_ksettings, 78448c2ecf20Sopenharmony_ci .set_link_ksettings = bnx2_set_link_ksettings, 78458c2ecf20Sopenharmony_ci}; 78468c2ecf20Sopenharmony_ci 78478c2ecf20Sopenharmony_ci/* Called with rtnl_lock */ 78488c2ecf20Sopenharmony_cistatic int 78498c2ecf20Sopenharmony_cibnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 78508c2ecf20Sopenharmony_ci{ 78518c2ecf20Sopenharmony_ci struct mii_ioctl_data *data = if_mii(ifr); 78528c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 78538c2ecf20Sopenharmony_ci int err; 78548c2ecf20Sopenharmony_ci 78558c2ecf20Sopenharmony_ci switch(cmd) { 78568c2ecf20Sopenharmony_ci case SIOCGMIIPHY: 78578c2ecf20Sopenharmony_ci data->phy_id = bp->phy_addr; 78588c2ecf20Sopenharmony_ci 78598c2ecf20Sopenharmony_ci fallthrough; 78608c2ecf20Sopenharmony_ci case SIOCGMIIREG: { 78618c2ecf20Sopenharmony_ci u32 mii_regval; 78628c2ecf20Sopenharmony_ci 78638c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) 78648c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 78658c2ecf20Sopenharmony_ci 78668c2ecf20Sopenharmony_ci if (!netif_running(dev)) 78678c2ecf20Sopenharmony_ci return -EAGAIN; 78688c2ecf20Sopenharmony_ci 78698c2ecf20Sopenharmony_ci spin_lock_bh(&bp->phy_lock); 78708c2ecf20Sopenharmony_ci err = bnx2_read_phy(bp, data->reg_num & 0x1f, &mii_regval); 78718c2ecf20Sopenharmony_ci spin_unlock_bh(&bp->phy_lock); 78728c2ecf20Sopenharmony_ci 78738c2ecf20Sopenharmony_ci data->val_out = mii_regval; 78748c2ecf20Sopenharmony_ci 78758c2ecf20Sopenharmony_ci return err; 78768c2ecf20Sopenharmony_ci } 78778c2ecf20Sopenharmony_ci 78788c2ecf20Sopenharmony_ci case SIOCSMIIREG: 78798c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_REMOTE_PHY_CAP) 78808c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 78818c2ecf20Sopenharmony_ci 78828c2ecf20Sopenharmony_ci if (!netif_running(dev)) 78838c2ecf20Sopenharmony_ci return -EAGAIN; 78848c2ecf20Sopenharmony_ci 78858c2ecf20Sopenharmony_ci spin_lock_bh(&bp->phy_lock); 78868c2ecf20Sopenharmony_ci err = bnx2_write_phy(bp, data->reg_num & 0x1f, data->val_in); 78878c2ecf20Sopenharmony_ci spin_unlock_bh(&bp->phy_lock); 78888c2ecf20Sopenharmony_ci 78898c2ecf20Sopenharmony_ci return err; 78908c2ecf20Sopenharmony_ci 78918c2ecf20Sopenharmony_ci default: 78928c2ecf20Sopenharmony_ci /* do nothing */ 78938c2ecf20Sopenharmony_ci break; 78948c2ecf20Sopenharmony_ci } 78958c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 78968c2ecf20Sopenharmony_ci} 78978c2ecf20Sopenharmony_ci 78988c2ecf20Sopenharmony_ci/* Called with rtnl_lock */ 78998c2ecf20Sopenharmony_cistatic int 79008c2ecf20Sopenharmony_cibnx2_change_mac_addr(struct net_device *dev, void *p) 79018c2ecf20Sopenharmony_ci{ 79028c2ecf20Sopenharmony_ci struct sockaddr *addr = p; 79038c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 79048c2ecf20Sopenharmony_ci 79058c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(addr->sa_data)) 79068c2ecf20Sopenharmony_ci return -EADDRNOTAVAIL; 79078c2ecf20Sopenharmony_ci 79088c2ecf20Sopenharmony_ci memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); 79098c2ecf20Sopenharmony_ci if (netif_running(dev)) 79108c2ecf20Sopenharmony_ci bnx2_set_mac_addr(bp, bp->dev->dev_addr, 0); 79118c2ecf20Sopenharmony_ci 79128c2ecf20Sopenharmony_ci return 0; 79138c2ecf20Sopenharmony_ci} 79148c2ecf20Sopenharmony_ci 79158c2ecf20Sopenharmony_ci/* Called with rtnl_lock */ 79168c2ecf20Sopenharmony_cistatic int 79178c2ecf20Sopenharmony_cibnx2_change_mtu(struct net_device *dev, int new_mtu) 79188c2ecf20Sopenharmony_ci{ 79198c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 79208c2ecf20Sopenharmony_ci 79218c2ecf20Sopenharmony_ci dev->mtu = new_mtu; 79228c2ecf20Sopenharmony_ci return bnx2_change_ring_size(bp, bp->rx_ring_size, bp->tx_ring_size, 79238c2ecf20Sopenharmony_ci false); 79248c2ecf20Sopenharmony_ci} 79258c2ecf20Sopenharmony_ci 79268c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 79278c2ecf20Sopenharmony_cistatic void 79288c2ecf20Sopenharmony_cipoll_bnx2(struct net_device *dev) 79298c2ecf20Sopenharmony_ci{ 79308c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 79318c2ecf20Sopenharmony_ci int i; 79328c2ecf20Sopenharmony_ci 79338c2ecf20Sopenharmony_ci for (i = 0; i < bp->irq_nvecs; i++) { 79348c2ecf20Sopenharmony_ci struct bnx2_irq *irq = &bp->irq_tbl[i]; 79358c2ecf20Sopenharmony_ci 79368c2ecf20Sopenharmony_ci disable_irq(irq->vector); 79378c2ecf20Sopenharmony_ci irq->handler(irq->vector, &bp->bnx2_napi[i]); 79388c2ecf20Sopenharmony_ci enable_irq(irq->vector); 79398c2ecf20Sopenharmony_ci } 79408c2ecf20Sopenharmony_ci} 79418c2ecf20Sopenharmony_ci#endif 79428c2ecf20Sopenharmony_ci 79438c2ecf20Sopenharmony_cistatic void 79448c2ecf20Sopenharmony_cibnx2_get_5709_media(struct bnx2 *bp) 79458c2ecf20Sopenharmony_ci{ 79468c2ecf20Sopenharmony_ci u32 val = BNX2_RD(bp, BNX2_MISC_DUAL_MEDIA_CTRL); 79478c2ecf20Sopenharmony_ci u32 bond_id = val & BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID; 79488c2ecf20Sopenharmony_ci u32 strap; 79498c2ecf20Sopenharmony_ci 79508c2ecf20Sopenharmony_ci if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_C) 79518c2ecf20Sopenharmony_ci return; 79528c2ecf20Sopenharmony_ci else if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_S) { 79538c2ecf20Sopenharmony_ci bp->phy_flags |= BNX2_PHY_FLAG_SERDES; 79548c2ecf20Sopenharmony_ci return; 79558c2ecf20Sopenharmony_ci } 79568c2ecf20Sopenharmony_ci 79578c2ecf20Sopenharmony_ci if (val & BNX2_MISC_DUAL_MEDIA_CTRL_STRAP_OVERRIDE) 79588c2ecf20Sopenharmony_ci strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL) >> 21; 79598c2ecf20Sopenharmony_ci else 79608c2ecf20Sopenharmony_ci strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL_STRAP) >> 8; 79618c2ecf20Sopenharmony_ci 79628c2ecf20Sopenharmony_ci if (bp->func == 0) { 79638c2ecf20Sopenharmony_ci switch (strap) { 79648c2ecf20Sopenharmony_ci case 0x4: 79658c2ecf20Sopenharmony_ci case 0x5: 79668c2ecf20Sopenharmony_ci case 0x6: 79678c2ecf20Sopenharmony_ci bp->phy_flags |= BNX2_PHY_FLAG_SERDES; 79688c2ecf20Sopenharmony_ci return; 79698c2ecf20Sopenharmony_ci } 79708c2ecf20Sopenharmony_ci } else { 79718c2ecf20Sopenharmony_ci switch (strap) { 79728c2ecf20Sopenharmony_ci case 0x1: 79738c2ecf20Sopenharmony_ci case 0x2: 79748c2ecf20Sopenharmony_ci case 0x4: 79758c2ecf20Sopenharmony_ci bp->phy_flags |= BNX2_PHY_FLAG_SERDES; 79768c2ecf20Sopenharmony_ci return; 79778c2ecf20Sopenharmony_ci } 79788c2ecf20Sopenharmony_ci } 79798c2ecf20Sopenharmony_ci} 79808c2ecf20Sopenharmony_ci 79818c2ecf20Sopenharmony_cistatic void 79828c2ecf20Sopenharmony_cibnx2_get_pci_speed(struct bnx2 *bp) 79838c2ecf20Sopenharmony_ci{ 79848c2ecf20Sopenharmony_ci u32 reg; 79858c2ecf20Sopenharmony_ci 79868c2ecf20Sopenharmony_ci reg = BNX2_RD(bp, BNX2_PCICFG_MISC_STATUS); 79878c2ecf20Sopenharmony_ci if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) { 79888c2ecf20Sopenharmony_ci u32 clkreg; 79898c2ecf20Sopenharmony_ci 79908c2ecf20Sopenharmony_ci bp->flags |= BNX2_FLAG_PCIX; 79918c2ecf20Sopenharmony_ci 79928c2ecf20Sopenharmony_ci clkreg = BNX2_RD(bp, BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS); 79938c2ecf20Sopenharmony_ci 79948c2ecf20Sopenharmony_ci clkreg &= BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET; 79958c2ecf20Sopenharmony_ci switch (clkreg) { 79968c2ecf20Sopenharmony_ci case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ: 79978c2ecf20Sopenharmony_ci bp->bus_speed_mhz = 133; 79988c2ecf20Sopenharmony_ci break; 79998c2ecf20Sopenharmony_ci 80008c2ecf20Sopenharmony_ci case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ: 80018c2ecf20Sopenharmony_ci bp->bus_speed_mhz = 100; 80028c2ecf20Sopenharmony_ci break; 80038c2ecf20Sopenharmony_ci 80048c2ecf20Sopenharmony_ci case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ: 80058c2ecf20Sopenharmony_ci case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ: 80068c2ecf20Sopenharmony_ci bp->bus_speed_mhz = 66; 80078c2ecf20Sopenharmony_ci break; 80088c2ecf20Sopenharmony_ci 80098c2ecf20Sopenharmony_ci case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ: 80108c2ecf20Sopenharmony_ci case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ: 80118c2ecf20Sopenharmony_ci bp->bus_speed_mhz = 50; 80128c2ecf20Sopenharmony_ci break; 80138c2ecf20Sopenharmony_ci 80148c2ecf20Sopenharmony_ci case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW: 80158c2ecf20Sopenharmony_ci case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ: 80168c2ecf20Sopenharmony_ci case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ: 80178c2ecf20Sopenharmony_ci bp->bus_speed_mhz = 33; 80188c2ecf20Sopenharmony_ci break; 80198c2ecf20Sopenharmony_ci } 80208c2ecf20Sopenharmony_ci } 80218c2ecf20Sopenharmony_ci else { 80228c2ecf20Sopenharmony_ci if (reg & BNX2_PCICFG_MISC_STATUS_M66EN) 80238c2ecf20Sopenharmony_ci bp->bus_speed_mhz = 66; 80248c2ecf20Sopenharmony_ci else 80258c2ecf20Sopenharmony_ci bp->bus_speed_mhz = 33; 80268c2ecf20Sopenharmony_ci } 80278c2ecf20Sopenharmony_ci 80288c2ecf20Sopenharmony_ci if (reg & BNX2_PCICFG_MISC_STATUS_32BIT_DET) 80298c2ecf20Sopenharmony_ci bp->flags |= BNX2_FLAG_PCI_32BIT; 80308c2ecf20Sopenharmony_ci 80318c2ecf20Sopenharmony_ci} 80328c2ecf20Sopenharmony_ci 80338c2ecf20Sopenharmony_cistatic void 80348c2ecf20Sopenharmony_cibnx2_read_vpd_fw_ver(struct bnx2 *bp) 80358c2ecf20Sopenharmony_ci{ 80368c2ecf20Sopenharmony_ci int rc, i, j; 80378c2ecf20Sopenharmony_ci u8 *data; 80388c2ecf20Sopenharmony_ci unsigned int block_end, rosize, len; 80398c2ecf20Sopenharmony_ci 80408c2ecf20Sopenharmony_ci#define BNX2_VPD_NVRAM_OFFSET 0x300 80418c2ecf20Sopenharmony_ci#define BNX2_VPD_LEN 128 80428c2ecf20Sopenharmony_ci#define BNX2_MAX_VER_SLEN 30 80438c2ecf20Sopenharmony_ci 80448c2ecf20Sopenharmony_ci data = kmalloc(256, GFP_KERNEL); 80458c2ecf20Sopenharmony_ci if (!data) 80468c2ecf20Sopenharmony_ci return; 80478c2ecf20Sopenharmony_ci 80488c2ecf20Sopenharmony_ci rc = bnx2_nvram_read(bp, BNX2_VPD_NVRAM_OFFSET, data + BNX2_VPD_LEN, 80498c2ecf20Sopenharmony_ci BNX2_VPD_LEN); 80508c2ecf20Sopenharmony_ci if (rc) 80518c2ecf20Sopenharmony_ci goto vpd_done; 80528c2ecf20Sopenharmony_ci 80538c2ecf20Sopenharmony_ci for (i = 0; i < BNX2_VPD_LEN; i += 4) { 80548c2ecf20Sopenharmony_ci data[i] = data[i + BNX2_VPD_LEN + 3]; 80558c2ecf20Sopenharmony_ci data[i + 1] = data[i + BNX2_VPD_LEN + 2]; 80568c2ecf20Sopenharmony_ci data[i + 2] = data[i + BNX2_VPD_LEN + 1]; 80578c2ecf20Sopenharmony_ci data[i + 3] = data[i + BNX2_VPD_LEN]; 80588c2ecf20Sopenharmony_ci } 80598c2ecf20Sopenharmony_ci 80608c2ecf20Sopenharmony_ci i = pci_vpd_find_tag(data, 0, BNX2_VPD_LEN, PCI_VPD_LRDT_RO_DATA); 80618c2ecf20Sopenharmony_ci if (i < 0) 80628c2ecf20Sopenharmony_ci goto vpd_done; 80638c2ecf20Sopenharmony_ci 80648c2ecf20Sopenharmony_ci rosize = pci_vpd_lrdt_size(&data[i]); 80658c2ecf20Sopenharmony_ci i += PCI_VPD_LRDT_TAG_SIZE; 80668c2ecf20Sopenharmony_ci block_end = i + rosize; 80678c2ecf20Sopenharmony_ci 80688c2ecf20Sopenharmony_ci if (block_end > BNX2_VPD_LEN) 80698c2ecf20Sopenharmony_ci goto vpd_done; 80708c2ecf20Sopenharmony_ci 80718c2ecf20Sopenharmony_ci j = pci_vpd_find_info_keyword(data, i, rosize, 80728c2ecf20Sopenharmony_ci PCI_VPD_RO_KEYWORD_MFR_ID); 80738c2ecf20Sopenharmony_ci if (j < 0) 80748c2ecf20Sopenharmony_ci goto vpd_done; 80758c2ecf20Sopenharmony_ci 80768c2ecf20Sopenharmony_ci len = pci_vpd_info_field_size(&data[j]); 80778c2ecf20Sopenharmony_ci 80788c2ecf20Sopenharmony_ci j += PCI_VPD_INFO_FLD_HDR_SIZE; 80798c2ecf20Sopenharmony_ci if (j + len > block_end || len != 4 || 80808c2ecf20Sopenharmony_ci memcmp(&data[j], "1028", 4)) 80818c2ecf20Sopenharmony_ci goto vpd_done; 80828c2ecf20Sopenharmony_ci 80838c2ecf20Sopenharmony_ci j = pci_vpd_find_info_keyword(data, i, rosize, 80848c2ecf20Sopenharmony_ci PCI_VPD_RO_KEYWORD_VENDOR0); 80858c2ecf20Sopenharmony_ci if (j < 0) 80868c2ecf20Sopenharmony_ci goto vpd_done; 80878c2ecf20Sopenharmony_ci 80888c2ecf20Sopenharmony_ci len = pci_vpd_info_field_size(&data[j]); 80898c2ecf20Sopenharmony_ci 80908c2ecf20Sopenharmony_ci j += PCI_VPD_INFO_FLD_HDR_SIZE; 80918c2ecf20Sopenharmony_ci if (j + len > block_end || len > BNX2_MAX_VER_SLEN) 80928c2ecf20Sopenharmony_ci goto vpd_done; 80938c2ecf20Sopenharmony_ci 80948c2ecf20Sopenharmony_ci memcpy(bp->fw_version, &data[j], len); 80958c2ecf20Sopenharmony_ci bp->fw_version[len] = ' '; 80968c2ecf20Sopenharmony_ci 80978c2ecf20Sopenharmony_civpd_done: 80988c2ecf20Sopenharmony_ci kfree(data); 80998c2ecf20Sopenharmony_ci} 81008c2ecf20Sopenharmony_ci 81018c2ecf20Sopenharmony_cistatic int 81028c2ecf20Sopenharmony_cibnx2_init_board(struct pci_dev *pdev, struct net_device *dev) 81038c2ecf20Sopenharmony_ci{ 81048c2ecf20Sopenharmony_ci struct bnx2 *bp; 81058c2ecf20Sopenharmony_ci int rc, i, j; 81068c2ecf20Sopenharmony_ci u32 reg; 81078c2ecf20Sopenharmony_ci u64 dma_mask, persist_dma_mask; 81088c2ecf20Sopenharmony_ci int err; 81098c2ecf20Sopenharmony_ci 81108c2ecf20Sopenharmony_ci SET_NETDEV_DEV(dev, &pdev->dev); 81118c2ecf20Sopenharmony_ci bp = netdev_priv(dev); 81128c2ecf20Sopenharmony_ci 81138c2ecf20Sopenharmony_ci bp->flags = 0; 81148c2ecf20Sopenharmony_ci bp->phy_flags = 0; 81158c2ecf20Sopenharmony_ci 81168c2ecf20Sopenharmony_ci bp->temp_stats_blk = 81178c2ecf20Sopenharmony_ci kzalloc(sizeof(struct statistics_block), GFP_KERNEL); 81188c2ecf20Sopenharmony_ci 81198c2ecf20Sopenharmony_ci if (!bp->temp_stats_blk) { 81208c2ecf20Sopenharmony_ci rc = -ENOMEM; 81218c2ecf20Sopenharmony_ci goto err_out; 81228c2ecf20Sopenharmony_ci } 81238c2ecf20Sopenharmony_ci 81248c2ecf20Sopenharmony_ci /* enable device (incl. PCI PM wakeup), and bus-mastering */ 81258c2ecf20Sopenharmony_ci rc = pci_enable_device(pdev); 81268c2ecf20Sopenharmony_ci if (rc) { 81278c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Cannot enable PCI device, aborting\n"); 81288c2ecf20Sopenharmony_ci goto err_out; 81298c2ecf20Sopenharmony_ci } 81308c2ecf20Sopenharmony_ci 81318c2ecf20Sopenharmony_ci if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { 81328c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 81338c2ecf20Sopenharmony_ci "Cannot find PCI device base address, aborting\n"); 81348c2ecf20Sopenharmony_ci rc = -ENODEV; 81358c2ecf20Sopenharmony_ci goto err_out_disable; 81368c2ecf20Sopenharmony_ci } 81378c2ecf20Sopenharmony_ci 81388c2ecf20Sopenharmony_ci rc = pci_request_regions(pdev, DRV_MODULE_NAME); 81398c2ecf20Sopenharmony_ci if (rc) { 81408c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting\n"); 81418c2ecf20Sopenharmony_ci goto err_out_disable; 81428c2ecf20Sopenharmony_ci } 81438c2ecf20Sopenharmony_ci 81448c2ecf20Sopenharmony_ci pci_set_master(pdev); 81458c2ecf20Sopenharmony_ci 81468c2ecf20Sopenharmony_ci bp->pm_cap = pdev->pm_cap; 81478c2ecf20Sopenharmony_ci if (bp->pm_cap == 0) { 81488c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 81498c2ecf20Sopenharmony_ci "Cannot find power management capability, aborting\n"); 81508c2ecf20Sopenharmony_ci rc = -EIO; 81518c2ecf20Sopenharmony_ci goto err_out_release; 81528c2ecf20Sopenharmony_ci } 81538c2ecf20Sopenharmony_ci 81548c2ecf20Sopenharmony_ci bp->dev = dev; 81558c2ecf20Sopenharmony_ci bp->pdev = pdev; 81568c2ecf20Sopenharmony_ci 81578c2ecf20Sopenharmony_ci spin_lock_init(&bp->phy_lock); 81588c2ecf20Sopenharmony_ci spin_lock_init(&bp->indirect_lock); 81598c2ecf20Sopenharmony_ci#ifdef BCM_CNIC 81608c2ecf20Sopenharmony_ci mutex_init(&bp->cnic_lock); 81618c2ecf20Sopenharmony_ci#endif 81628c2ecf20Sopenharmony_ci INIT_WORK(&bp->reset_task, bnx2_reset_task); 81638c2ecf20Sopenharmony_ci 81648c2ecf20Sopenharmony_ci bp->regview = pci_iomap(pdev, 0, MB_GET_CID_ADDR(TX_TSS_CID + 81658c2ecf20Sopenharmony_ci TX_MAX_TSS_RINGS + 1)); 81668c2ecf20Sopenharmony_ci if (!bp->regview) { 81678c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Cannot map register space, aborting\n"); 81688c2ecf20Sopenharmony_ci rc = -ENOMEM; 81698c2ecf20Sopenharmony_ci goto err_out_release; 81708c2ecf20Sopenharmony_ci } 81718c2ecf20Sopenharmony_ci 81728c2ecf20Sopenharmony_ci /* Configure byte swap and enable write to the reg_window registers. 81738c2ecf20Sopenharmony_ci * Rely on CPU to do target byte swapping on big endian systems 81748c2ecf20Sopenharmony_ci * The chip's target access swapping will not swap all accesses 81758c2ecf20Sopenharmony_ci */ 81768c2ecf20Sopenharmony_ci BNX2_WR(bp, BNX2_PCICFG_MISC_CONFIG, 81778c2ecf20Sopenharmony_ci BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA | 81788c2ecf20Sopenharmony_ci BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP); 81798c2ecf20Sopenharmony_ci 81808c2ecf20Sopenharmony_ci bp->chip_id = BNX2_RD(bp, BNX2_MISC_ID); 81818c2ecf20Sopenharmony_ci 81828c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5709) { 81838c2ecf20Sopenharmony_ci if (!pci_is_pcie(pdev)) { 81848c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Not PCIE, aborting\n"); 81858c2ecf20Sopenharmony_ci rc = -EIO; 81868c2ecf20Sopenharmony_ci goto err_out_unmap; 81878c2ecf20Sopenharmony_ci } 81888c2ecf20Sopenharmony_ci bp->flags |= BNX2_FLAG_PCIE; 81898c2ecf20Sopenharmony_ci if (BNX2_CHIP_REV(bp) == BNX2_CHIP_REV_Ax) 81908c2ecf20Sopenharmony_ci bp->flags |= BNX2_FLAG_JUMBO_BROKEN; 81918c2ecf20Sopenharmony_ci 81928c2ecf20Sopenharmony_ci /* AER (Advanced Error Reporting) hooks */ 81938c2ecf20Sopenharmony_ci err = pci_enable_pcie_error_reporting(pdev); 81948c2ecf20Sopenharmony_ci if (!err) 81958c2ecf20Sopenharmony_ci bp->flags |= BNX2_FLAG_AER_ENABLED; 81968c2ecf20Sopenharmony_ci 81978c2ecf20Sopenharmony_ci } else { 81988c2ecf20Sopenharmony_ci bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX); 81998c2ecf20Sopenharmony_ci if (bp->pcix_cap == 0) { 82008c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 82018c2ecf20Sopenharmony_ci "Cannot find PCIX capability, aborting\n"); 82028c2ecf20Sopenharmony_ci rc = -EIO; 82038c2ecf20Sopenharmony_ci goto err_out_unmap; 82048c2ecf20Sopenharmony_ci } 82058c2ecf20Sopenharmony_ci bp->flags |= BNX2_FLAG_BROKEN_STATS; 82068c2ecf20Sopenharmony_ci } 82078c2ecf20Sopenharmony_ci 82088c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5709 && 82098c2ecf20Sopenharmony_ci BNX2_CHIP_REV(bp) != BNX2_CHIP_REV_Ax) { 82108c2ecf20Sopenharmony_ci if (pdev->msix_cap) 82118c2ecf20Sopenharmony_ci bp->flags |= BNX2_FLAG_MSIX_CAP; 82128c2ecf20Sopenharmony_ci } 82138c2ecf20Sopenharmony_ci 82148c2ecf20Sopenharmony_ci if (BNX2_CHIP_ID(bp) != BNX2_CHIP_ID_5706_A0 && 82158c2ecf20Sopenharmony_ci BNX2_CHIP_ID(bp) != BNX2_CHIP_ID_5706_A1) { 82168c2ecf20Sopenharmony_ci if (pdev->msi_cap) 82178c2ecf20Sopenharmony_ci bp->flags |= BNX2_FLAG_MSI_CAP; 82188c2ecf20Sopenharmony_ci } 82198c2ecf20Sopenharmony_ci 82208c2ecf20Sopenharmony_ci /* 5708 cannot support DMA addresses > 40-bit. */ 82218c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5708) 82228c2ecf20Sopenharmony_ci persist_dma_mask = dma_mask = DMA_BIT_MASK(40); 82238c2ecf20Sopenharmony_ci else 82248c2ecf20Sopenharmony_ci persist_dma_mask = dma_mask = DMA_BIT_MASK(64); 82258c2ecf20Sopenharmony_ci 82268c2ecf20Sopenharmony_ci /* Configure DMA attributes. */ 82278c2ecf20Sopenharmony_ci if (pci_set_dma_mask(pdev, dma_mask) == 0) { 82288c2ecf20Sopenharmony_ci dev->features |= NETIF_F_HIGHDMA; 82298c2ecf20Sopenharmony_ci rc = pci_set_consistent_dma_mask(pdev, persist_dma_mask); 82308c2ecf20Sopenharmony_ci if (rc) { 82318c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 82328c2ecf20Sopenharmony_ci "pci_set_consistent_dma_mask failed, aborting\n"); 82338c2ecf20Sopenharmony_ci goto err_out_unmap; 82348c2ecf20Sopenharmony_ci } 82358c2ecf20Sopenharmony_ci } else if ((rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) != 0) { 82368c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "System does not support DMA, aborting\n"); 82378c2ecf20Sopenharmony_ci goto err_out_unmap; 82388c2ecf20Sopenharmony_ci } 82398c2ecf20Sopenharmony_ci 82408c2ecf20Sopenharmony_ci if (!(bp->flags & BNX2_FLAG_PCIE)) 82418c2ecf20Sopenharmony_ci bnx2_get_pci_speed(bp); 82428c2ecf20Sopenharmony_ci 82438c2ecf20Sopenharmony_ci /* 5706A0 may falsely detect SERR and PERR. */ 82448c2ecf20Sopenharmony_ci if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) { 82458c2ecf20Sopenharmony_ci reg = BNX2_RD(bp, PCI_COMMAND); 82468c2ecf20Sopenharmony_ci reg &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY); 82478c2ecf20Sopenharmony_ci BNX2_WR(bp, PCI_COMMAND, reg); 82488c2ecf20Sopenharmony_ci } else if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A1) && 82498c2ecf20Sopenharmony_ci !(bp->flags & BNX2_FLAG_PCIX)) { 82508c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 82518c2ecf20Sopenharmony_ci "5706 A1 can only be used in a PCIX bus, aborting\n"); 82528c2ecf20Sopenharmony_ci rc = -EPERM; 82538c2ecf20Sopenharmony_ci goto err_out_unmap; 82548c2ecf20Sopenharmony_ci } 82558c2ecf20Sopenharmony_ci 82568c2ecf20Sopenharmony_ci bnx2_init_nvram(bp); 82578c2ecf20Sopenharmony_ci 82588c2ecf20Sopenharmony_ci reg = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_SIGNATURE); 82598c2ecf20Sopenharmony_ci 82608c2ecf20Sopenharmony_ci if (bnx2_reg_rd_ind(bp, BNX2_MCP_TOE_ID) & BNX2_MCP_TOE_ID_FUNCTION_ID) 82618c2ecf20Sopenharmony_ci bp->func = 1; 82628c2ecf20Sopenharmony_ci 82638c2ecf20Sopenharmony_ci if ((reg & BNX2_SHM_HDR_SIGNATURE_SIG_MASK) == 82648c2ecf20Sopenharmony_ci BNX2_SHM_HDR_SIGNATURE_SIG) { 82658c2ecf20Sopenharmony_ci u32 off = bp->func << 2; 82668c2ecf20Sopenharmony_ci 82678c2ecf20Sopenharmony_ci bp->shmem_base = bnx2_reg_rd_ind(bp, BNX2_SHM_HDR_ADDR_0 + off); 82688c2ecf20Sopenharmony_ci } else 82698c2ecf20Sopenharmony_ci bp->shmem_base = HOST_VIEW_SHMEM_BASE; 82708c2ecf20Sopenharmony_ci 82718c2ecf20Sopenharmony_ci /* Get the permanent MAC address. First we need to make sure the 82728c2ecf20Sopenharmony_ci * firmware is actually running. 82738c2ecf20Sopenharmony_ci */ 82748c2ecf20Sopenharmony_ci reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_SIGNATURE); 82758c2ecf20Sopenharmony_ci 82768c2ecf20Sopenharmony_ci if ((reg & BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK) != 82778c2ecf20Sopenharmony_ci BNX2_DEV_INFO_SIGNATURE_MAGIC) { 82788c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Firmware not running, aborting\n"); 82798c2ecf20Sopenharmony_ci rc = -ENODEV; 82808c2ecf20Sopenharmony_ci goto err_out_unmap; 82818c2ecf20Sopenharmony_ci } 82828c2ecf20Sopenharmony_ci 82838c2ecf20Sopenharmony_ci bnx2_read_vpd_fw_ver(bp); 82848c2ecf20Sopenharmony_ci 82858c2ecf20Sopenharmony_ci j = strlen(bp->fw_version); 82868c2ecf20Sopenharmony_ci reg = bnx2_shmem_rd(bp, BNX2_DEV_INFO_BC_REV); 82878c2ecf20Sopenharmony_ci for (i = 0; i < 3 && j < 24; i++) { 82888c2ecf20Sopenharmony_ci u8 num, k, skip0; 82898c2ecf20Sopenharmony_ci 82908c2ecf20Sopenharmony_ci if (i == 0) { 82918c2ecf20Sopenharmony_ci bp->fw_version[j++] = 'b'; 82928c2ecf20Sopenharmony_ci bp->fw_version[j++] = 'c'; 82938c2ecf20Sopenharmony_ci bp->fw_version[j++] = ' '; 82948c2ecf20Sopenharmony_ci } 82958c2ecf20Sopenharmony_ci num = (u8) (reg >> (24 - (i * 8))); 82968c2ecf20Sopenharmony_ci for (k = 100, skip0 = 1; k >= 1; num %= k, k /= 10) { 82978c2ecf20Sopenharmony_ci if (num >= k || !skip0 || k == 1) { 82988c2ecf20Sopenharmony_ci bp->fw_version[j++] = (num / k) + '0'; 82998c2ecf20Sopenharmony_ci skip0 = 0; 83008c2ecf20Sopenharmony_ci } 83018c2ecf20Sopenharmony_ci } 83028c2ecf20Sopenharmony_ci if (i != 2) 83038c2ecf20Sopenharmony_ci bp->fw_version[j++] = '.'; 83048c2ecf20Sopenharmony_ci } 83058c2ecf20Sopenharmony_ci reg = bnx2_shmem_rd(bp, BNX2_PORT_FEATURE); 83068c2ecf20Sopenharmony_ci if (reg & BNX2_PORT_FEATURE_WOL_ENABLED) 83078c2ecf20Sopenharmony_ci bp->wol = 1; 83088c2ecf20Sopenharmony_ci 83098c2ecf20Sopenharmony_ci if (reg & BNX2_PORT_FEATURE_ASF_ENABLED) { 83108c2ecf20Sopenharmony_ci bp->flags |= BNX2_FLAG_ASF_ENABLE; 83118c2ecf20Sopenharmony_ci 83128c2ecf20Sopenharmony_ci for (i = 0; i < 30; i++) { 83138c2ecf20Sopenharmony_ci reg = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION); 83148c2ecf20Sopenharmony_ci if (reg & BNX2_CONDITION_MFW_RUN_MASK) 83158c2ecf20Sopenharmony_ci break; 83168c2ecf20Sopenharmony_ci msleep(10); 83178c2ecf20Sopenharmony_ci } 83188c2ecf20Sopenharmony_ci } 83198c2ecf20Sopenharmony_ci reg = bnx2_shmem_rd(bp, BNX2_BC_STATE_CONDITION); 83208c2ecf20Sopenharmony_ci reg &= BNX2_CONDITION_MFW_RUN_MASK; 83218c2ecf20Sopenharmony_ci if (reg != BNX2_CONDITION_MFW_RUN_UNKNOWN && 83228c2ecf20Sopenharmony_ci reg != BNX2_CONDITION_MFW_RUN_NONE) { 83238c2ecf20Sopenharmony_ci u32 addr = bnx2_shmem_rd(bp, BNX2_MFW_VER_PTR); 83248c2ecf20Sopenharmony_ci 83258c2ecf20Sopenharmony_ci if (j < 32) 83268c2ecf20Sopenharmony_ci bp->fw_version[j++] = ' '; 83278c2ecf20Sopenharmony_ci for (i = 0; i < 3 && j < 28; i++) { 83288c2ecf20Sopenharmony_ci reg = bnx2_reg_rd_ind(bp, addr + i * 4); 83298c2ecf20Sopenharmony_ci reg = be32_to_cpu(reg); 83308c2ecf20Sopenharmony_ci memcpy(&bp->fw_version[j], ®, 4); 83318c2ecf20Sopenharmony_ci j += 4; 83328c2ecf20Sopenharmony_ci } 83338c2ecf20Sopenharmony_ci } 83348c2ecf20Sopenharmony_ci 83358c2ecf20Sopenharmony_ci reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_MAC_UPPER); 83368c2ecf20Sopenharmony_ci bp->mac_addr[0] = (u8) (reg >> 8); 83378c2ecf20Sopenharmony_ci bp->mac_addr[1] = (u8) reg; 83388c2ecf20Sopenharmony_ci 83398c2ecf20Sopenharmony_ci reg = bnx2_shmem_rd(bp, BNX2_PORT_HW_CFG_MAC_LOWER); 83408c2ecf20Sopenharmony_ci bp->mac_addr[2] = (u8) (reg >> 24); 83418c2ecf20Sopenharmony_ci bp->mac_addr[3] = (u8) (reg >> 16); 83428c2ecf20Sopenharmony_ci bp->mac_addr[4] = (u8) (reg >> 8); 83438c2ecf20Sopenharmony_ci bp->mac_addr[5] = (u8) reg; 83448c2ecf20Sopenharmony_ci 83458c2ecf20Sopenharmony_ci bp->tx_ring_size = BNX2_MAX_TX_DESC_CNT; 83468c2ecf20Sopenharmony_ci bnx2_set_rx_ring_size(bp, 255); 83478c2ecf20Sopenharmony_ci 83488c2ecf20Sopenharmony_ci bp->tx_quick_cons_trip_int = 2; 83498c2ecf20Sopenharmony_ci bp->tx_quick_cons_trip = 20; 83508c2ecf20Sopenharmony_ci bp->tx_ticks_int = 18; 83518c2ecf20Sopenharmony_ci bp->tx_ticks = 80; 83528c2ecf20Sopenharmony_ci 83538c2ecf20Sopenharmony_ci bp->rx_quick_cons_trip_int = 2; 83548c2ecf20Sopenharmony_ci bp->rx_quick_cons_trip = 12; 83558c2ecf20Sopenharmony_ci bp->rx_ticks_int = 18; 83568c2ecf20Sopenharmony_ci bp->rx_ticks = 18; 83578c2ecf20Sopenharmony_ci 83588c2ecf20Sopenharmony_ci bp->stats_ticks = USEC_PER_SEC & BNX2_HC_STATS_TICKS_HC_STAT_TICKS; 83598c2ecf20Sopenharmony_ci 83608c2ecf20Sopenharmony_ci bp->current_interval = BNX2_TIMER_INTERVAL; 83618c2ecf20Sopenharmony_ci 83628c2ecf20Sopenharmony_ci bp->phy_addr = 1; 83638c2ecf20Sopenharmony_ci 83648c2ecf20Sopenharmony_ci /* allocate stats_blk */ 83658c2ecf20Sopenharmony_ci rc = bnx2_alloc_stats_blk(dev); 83668c2ecf20Sopenharmony_ci if (rc) 83678c2ecf20Sopenharmony_ci goto err_out_unmap; 83688c2ecf20Sopenharmony_ci 83698c2ecf20Sopenharmony_ci /* Disable WOL support if we are running on a SERDES chip. */ 83708c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5709) 83718c2ecf20Sopenharmony_ci bnx2_get_5709_media(bp); 83728c2ecf20Sopenharmony_ci else if (BNX2_CHIP_BOND(bp) & BNX2_CHIP_BOND_SERDES_BIT) 83738c2ecf20Sopenharmony_ci bp->phy_flags |= BNX2_PHY_FLAG_SERDES; 83748c2ecf20Sopenharmony_ci 83758c2ecf20Sopenharmony_ci bp->phy_port = PORT_TP; 83768c2ecf20Sopenharmony_ci if (bp->phy_flags & BNX2_PHY_FLAG_SERDES) { 83778c2ecf20Sopenharmony_ci bp->phy_port = PORT_FIBRE; 83788c2ecf20Sopenharmony_ci reg = bnx2_shmem_rd(bp, BNX2_SHARED_HW_CFG_CONFIG); 83798c2ecf20Sopenharmony_ci if (!(reg & BNX2_SHARED_HW_CFG_GIG_LINK_ON_VAUX)) { 83808c2ecf20Sopenharmony_ci bp->flags |= BNX2_FLAG_NO_WOL; 83818c2ecf20Sopenharmony_ci bp->wol = 0; 83828c2ecf20Sopenharmony_ci } 83838c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5706) { 83848c2ecf20Sopenharmony_ci /* Don't do parallel detect on this board because of 83858c2ecf20Sopenharmony_ci * some board problems. The link will not go down 83868c2ecf20Sopenharmony_ci * if we do parallel detect. 83878c2ecf20Sopenharmony_ci */ 83888c2ecf20Sopenharmony_ci if (pdev->subsystem_vendor == PCI_VENDOR_ID_HP && 83898c2ecf20Sopenharmony_ci pdev->subsystem_device == 0x310c) 83908c2ecf20Sopenharmony_ci bp->phy_flags |= BNX2_PHY_FLAG_NO_PARALLEL; 83918c2ecf20Sopenharmony_ci } else { 83928c2ecf20Sopenharmony_ci bp->phy_addr = 2; 83938c2ecf20Sopenharmony_ci if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G) 83948c2ecf20Sopenharmony_ci bp->phy_flags |= BNX2_PHY_FLAG_2_5G_CAPABLE; 83958c2ecf20Sopenharmony_ci } 83968c2ecf20Sopenharmony_ci } else if (BNX2_CHIP(bp) == BNX2_CHIP_5706 || 83978c2ecf20Sopenharmony_ci BNX2_CHIP(bp) == BNX2_CHIP_5708) 83988c2ecf20Sopenharmony_ci bp->phy_flags |= BNX2_PHY_FLAG_CRC_FIX; 83998c2ecf20Sopenharmony_ci else if (BNX2_CHIP(bp) == BNX2_CHIP_5709 && 84008c2ecf20Sopenharmony_ci (BNX2_CHIP_REV(bp) == BNX2_CHIP_REV_Ax || 84018c2ecf20Sopenharmony_ci BNX2_CHIP_REV(bp) == BNX2_CHIP_REV_Bx)) 84028c2ecf20Sopenharmony_ci bp->phy_flags |= BNX2_PHY_FLAG_DIS_EARLY_DAC; 84038c2ecf20Sopenharmony_ci 84048c2ecf20Sopenharmony_ci bnx2_init_fw_cap(bp); 84058c2ecf20Sopenharmony_ci 84068c2ecf20Sopenharmony_ci if ((BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_A0) || 84078c2ecf20Sopenharmony_ci (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_B0) || 84088c2ecf20Sopenharmony_ci (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5708_B1) || 84098c2ecf20Sopenharmony_ci !(BNX2_RD(bp, BNX2_PCI_CONFIG_3) & BNX2_PCI_CONFIG_3_VAUX_PRESET)) { 84108c2ecf20Sopenharmony_ci bp->flags |= BNX2_FLAG_NO_WOL; 84118c2ecf20Sopenharmony_ci bp->wol = 0; 84128c2ecf20Sopenharmony_ci } 84138c2ecf20Sopenharmony_ci 84148c2ecf20Sopenharmony_ci if (bp->flags & BNX2_FLAG_NO_WOL) 84158c2ecf20Sopenharmony_ci device_set_wakeup_capable(&bp->pdev->dev, false); 84168c2ecf20Sopenharmony_ci else 84178c2ecf20Sopenharmony_ci device_set_wakeup_enable(&bp->pdev->dev, bp->wol); 84188c2ecf20Sopenharmony_ci 84198c2ecf20Sopenharmony_ci if (BNX2_CHIP_ID(bp) == BNX2_CHIP_ID_5706_A0) { 84208c2ecf20Sopenharmony_ci bp->tx_quick_cons_trip_int = 84218c2ecf20Sopenharmony_ci bp->tx_quick_cons_trip; 84228c2ecf20Sopenharmony_ci bp->tx_ticks_int = bp->tx_ticks; 84238c2ecf20Sopenharmony_ci bp->rx_quick_cons_trip_int = 84248c2ecf20Sopenharmony_ci bp->rx_quick_cons_trip; 84258c2ecf20Sopenharmony_ci bp->rx_ticks_int = bp->rx_ticks; 84268c2ecf20Sopenharmony_ci bp->comp_prod_trip_int = bp->comp_prod_trip; 84278c2ecf20Sopenharmony_ci bp->com_ticks_int = bp->com_ticks; 84288c2ecf20Sopenharmony_ci bp->cmd_ticks_int = bp->cmd_ticks; 84298c2ecf20Sopenharmony_ci } 84308c2ecf20Sopenharmony_ci 84318c2ecf20Sopenharmony_ci /* Disable MSI on 5706 if AMD 8132 bridge is found. 84328c2ecf20Sopenharmony_ci * 84338c2ecf20Sopenharmony_ci * MSI is defined to be 32-bit write. The 5706 does 64-bit MSI writes 84348c2ecf20Sopenharmony_ci * with byte enables disabled on the unused 32-bit word. This is legal 84358c2ecf20Sopenharmony_ci * but causes problems on the AMD 8132 which will eventually stop 84368c2ecf20Sopenharmony_ci * responding after a while. 84378c2ecf20Sopenharmony_ci * 84388c2ecf20Sopenharmony_ci * AMD believes this incompatibility is unique to the 5706, and 84398c2ecf20Sopenharmony_ci * prefers to locally disable MSI rather than globally disabling it. 84408c2ecf20Sopenharmony_ci */ 84418c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5706 && disable_msi == 0) { 84428c2ecf20Sopenharmony_ci struct pci_dev *amd_8132 = NULL; 84438c2ecf20Sopenharmony_ci 84448c2ecf20Sopenharmony_ci while ((amd_8132 = pci_get_device(PCI_VENDOR_ID_AMD, 84458c2ecf20Sopenharmony_ci PCI_DEVICE_ID_AMD_8132_BRIDGE, 84468c2ecf20Sopenharmony_ci amd_8132))) { 84478c2ecf20Sopenharmony_ci 84488c2ecf20Sopenharmony_ci if (amd_8132->revision >= 0x10 && 84498c2ecf20Sopenharmony_ci amd_8132->revision <= 0x13) { 84508c2ecf20Sopenharmony_ci disable_msi = 1; 84518c2ecf20Sopenharmony_ci pci_dev_put(amd_8132); 84528c2ecf20Sopenharmony_ci break; 84538c2ecf20Sopenharmony_ci } 84548c2ecf20Sopenharmony_ci } 84558c2ecf20Sopenharmony_ci } 84568c2ecf20Sopenharmony_ci 84578c2ecf20Sopenharmony_ci bnx2_set_default_link(bp); 84588c2ecf20Sopenharmony_ci bp->req_flow_ctrl = FLOW_CTRL_RX | FLOW_CTRL_TX; 84598c2ecf20Sopenharmony_ci 84608c2ecf20Sopenharmony_ci timer_setup(&bp->timer, bnx2_timer, 0); 84618c2ecf20Sopenharmony_ci bp->timer.expires = RUN_AT(BNX2_TIMER_INTERVAL); 84628c2ecf20Sopenharmony_ci 84638c2ecf20Sopenharmony_ci#ifdef BCM_CNIC 84648c2ecf20Sopenharmony_ci if (bnx2_shmem_rd(bp, BNX2_ISCSI_INITIATOR) & BNX2_ISCSI_INITIATOR_EN) 84658c2ecf20Sopenharmony_ci bp->cnic_eth_dev.max_iscsi_conn = 84668c2ecf20Sopenharmony_ci (bnx2_shmem_rd(bp, BNX2_ISCSI_MAX_CONN) & 84678c2ecf20Sopenharmony_ci BNX2_ISCSI_MAX_CONN_MASK) >> BNX2_ISCSI_MAX_CONN_SHIFT; 84688c2ecf20Sopenharmony_ci bp->cnic_probe = bnx2_cnic_probe; 84698c2ecf20Sopenharmony_ci#endif 84708c2ecf20Sopenharmony_ci pci_save_state(pdev); 84718c2ecf20Sopenharmony_ci 84728c2ecf20Sopenharmony_ci return 0; 84738c2ecf20Sopenharmony_ci 84748c2ecf20Sopenharmony_cierr_out_unmap: 84758c2ecf20Sopenharmony_ci if (bp->flags & BNX2_FLAG_AER_ENABLED) { 84768c2ecf20Sopenharmony_ci pci_disable_pcie_error_reporting(pdev); 84778c2ecf20Sopenharmony_ci bp->flags &= ~BNX2_FLAG_AER_ENABLED; 84788c2ecf20Sopenharmony_ci } 84798c2ecf20Sopenharmony_ci 84808c2ecf20Sopenharmony_ci pci_iounmap(pdev, bp->regview); 84818c2ecf20Sopenharmony_ci bp->regview = NULL; 84828c2ecf20Sopenharmony_ci 84838c2ecf20Sopenharmony_cierr_out_release: 84848c2ecf20Sopenharmony_ci pci_release_regions(pdev); 84858c2ecf20Sopenharmony_ci 84868c2ecf20Sopenharmony_cierr_out_disable: 84878c2ecf20Sopenharmony_ci pci_disable_device(pdev); 84888c2ecf20Sopenharmony_ci 84898c2ecf20Sopenharmony_cierr_out: 84908c2ecf20Sopenharmony_ci kfree(bp->temp_stats_blk); 84918c2ecf20Sopenharmony_ci 84928c2ecf20Sopenharmony_ci return rc; 84938c2ecf20Sopenharmony_ci} 84948c2ecf20Sopenharmony_ci 84958c2ecf20Sopenharmony_cistatic char * 84968c2ecf20Sopenharmony_cibnx2_bus_string(struct bnx2 *bp, char *str) 84978c2ecf20Sopenharmony_ci{ 84988c2ecf20Sopenharmony_ci char *s = str; 84998c2ecf20Sopenharmony_ci 85008c2ecf20Sopenharmony_ci if (bp->flags & BNX2_FLAG_PCIE) { 85018c2ecf20Sopenharmony_ci s += sprintf(s, "PCI Express"); 85028c2ecf20Sopenharmony_ci } else { 85038c2ecf20Sopenharmony_ci s += sprintf(s, "PCI"); 85048c2ecf20Sopenharmony_ci if (bp->flags & BNX2_FLAG_PCIX) 85058c2ecf20Sopenharmony_ci s += sprintf(s, "-X"); 85068c2ecf20Sopenharmony_ci if (bp->flags & BNX2_FLAG_PCI_32BIT) 85078c2ecf20Sopenharmony_ci s += sprintf(s, " 32-bit"); 85088c2ecf20Sopenharmony_ci else 85098c2ecf20Sopenharmony_ci s += sprintf(s, " 64-bit"); 85108c2ecf20Sopenharmony_ci s += sprintf(s, " %dMHz", bp->bus_speed_mhz); 85118c2ecf20Sopenharmony_ci } 85128c2ecf20Sopenharmony_ci return str; 85138c2ecf20Sopenharmony_ci} 85148c2ecf20Sopenharmony_ci 85158c2ecf20Sopenharmony_cistatic void 85168c2ecf20Sopenharmony_cibnx2_del_napi(struct bnx2 *bp) 85178c2ecf20Sopenharmony_ci{ 85188c2ecf20Sopenharmony_ci int i; 85198c2ecf20Sopenharmony_ci 85208c2ecf20Sopenharmony_ci for (i = 0; i < bp->irq_nvecs; i++) 85218c2ecf20Sopenharmony_ci netif_napi_del(&bp->bnx2_napi[i].napi); 85228c2ecf20Sopenharmony_ci} 85238c2ecf20Sopenharmony_ci 85248c2ecf20Sopenharmony_cistatic void 85258c2ecf20Sopenharmony_cibnx2_init_napi(struct bnx2 *bp) 85268c2ecf20Sopenharmony_ci{ 85278c2ecf20Sopenharmony_ci int i; 85288c2ecf20Sopenharmony_ci 85298c2ecf20Sopenharmony_ci for (i = 0; i < bp->irq_nvecs; i++) { 85308c2ecf20Sopenharmony_ci struct bnx2_napi *bnapi = &bp->bnx2_napi[i]; 85318c2ecf20Sopenharmony_ci int (*poll)(struct napi_struct *, int); 85328c2ecf20Sopenharmony_ci 85338c2ecf20Sopenharmony_ci if (i == 0) 85348c2ecf20Sopenharmony_ci poll = bnx2_poll; 85358c2ecf20Sopenharmony_ci else 85368c2ecf20Sopenharmony_ci poll = bnx2_poll_msix; 85378c2ecf20Sopenharmony_ci 85388c2ecf20Sopenharmony_ci netif_napi_add(bp->dev, &bp->bnx2_napi[i].napi, poll, 64); 85398c2ecf20Sopenharmony_ci bnapi->bp = bp; 85408c2ecf20Sopenharmony_ci } 85418c2ecf20Sopenharmony_ci} 85428c2ecf20Sopenharmony_ci 85438c2ecf20Sopenharmony_cistatic const struct net_device_ops bnx2_netdev_ops = { 85448c2ecf20Sopenharmony_ci .ndo_open = bnx2_open, 85458c2ecf20Sopenharmony_ci .ndo_start_xmit = bnx2_start_xmit, 85468c2ecf20Sopenharmony_ci .ndo_stop = bnx2_close, 85478c2ecf20Sopenharmony_ci .ndo_get_stats64 = bnx2_get_stats64, 85488c2ecf20Sopenharmony_ci .ndo_set_rx_mode = bnx2_set_rx_mode, 85498c2ecf20Sopenharmony_ci .ndo_do_ioctl = bnx2_ioctl, 85508c2ecf20Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 85518c2ecf20Sopenharmony_ci .ndo_set_mac_address = bnx2_change_mac_addr, 85528c2ecf20Sopenharmony_ci .ndo_change_mtu = bnx2_change_mtu, 85538c2ecf20Sopenharmony_ci .ndo_set_features = bnx2_set_features, 85548c2ecf20Sopenharmony_ci .ndo_tx_timeout = bnx2_tx_timeout, 85558c2ecf20Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 85568c2ecf20Sopenharmony_ci .ndo_poll_controller = poll_bnx2, 85578c2ecf20Sopenharmony_ci#endif 85588c2ecf20Sopenharmony_ci}; 85598c2ecf20Sopenharmony_ci 85608c2ecf20Sopenharmony_cistatic int 85618c2ecf20Sopenharmony_cibnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) 85628c2ecf20Sopenharmony_ci{ 85638c2ecf20Sopenharmony_ci struct net_device *dev; 85648c2ecf20Sopenharmony_ci struct bnx2 *bp; 85658c2ecf20Sopenharmony_ci int rc; 85668c2ecf20Sopenharmony_ci char str[40]; 85678c2ecf20Sopenharmony_ci 85688c2ecf20Sopenharmony_ci /* dev zeroed in init_etherdev */ 85698c2ecf20Sopenharmony_ci dev = alloc_etherdev_mq(sizeof(*bp), TX_MAX_RINGS); 85708c2ecf20Sopenharmony_ci if (!dev) 85718c2ecf20Sopenharmony_ci return -ENOMEM; 85728c2ecf20Sopenharmony_ci 85738c2ecf20Sopenharmony_ci rc = bnx2_init_board(pdev, dev); 85748c2ecf20Sopenharmony_ci if (rc < 0) 85758c2ecf20Sopenharmony_ci goto err_free; 85768c2ecf20Sopenharmony_ci 85778c2ecf20Sopenharmony_ci dev->netdev_ops = &bnx2_netdev_ops; 85788c2ecf20Sopenharmony_ci dev->watchdog_timeo = TX_TIMEOUT; 85798c2ecf20Sopenharmony_ci dev->ethtool_ops = &bnx2_ethtool_ops; 85808c2ecf20Sopenharmony_ci 85818c2ecf20Sopenharmony_ci bp = netdev_priv(dev); 85828c2ecf20Sopenharmony_ci 85838c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, dev); 85848c2ecf20Sopenharmony_ci 85858c2ecf20Sopenharmony_ci /* 85868c2ecf20Sopenharmony_ci * In-flight DMA from 1st kernel could continue going in kdump kernel. 85878c2ecf20Sopenharmony_ci * New io-page table has been created before bnx2 does reset at open stage. 85888c2ecf20Sopenharmony_ci * We have to wait for the in-flight DMA to complete to avoid it look up 85898c2ecf20Sopenharmony_ci * into the newly created io-page table. 85908c2ecf20Sopenharmony_ci */ 85918c2ecf20Sopenharmony_ci if (is_kdump_kernel()) 85928c2ecf20Sopenharmony_ci bnx2_wait_dma_complete(bp); 85938c2ecf20Sopenharmony_ci 85948c2ecf20Sopenharmony_ci memcpy(dev->dev_addr, bp->mac_addr, ETH_ALEN); 85958c2ecf20Sopenharmony_ci 85968c2ecf20Sopenharmony_ci dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | 85978c2ecf20Sopenharmony_ci NETIF_F_TSO | NETIF_F_TSO_ECN | 85988c2ecf20Sopenharmony_ci NETIF_F_RXHASH | NETIF_F_RXCSUM; 85998c2ecf20Sopenharmony_ci 86008c2ecf20Sopenharmony_ci if (BNX2_CHIP(bp) == BNX2_CHIP_5709) 86018c2ecf20Sopenharmony_ci dev->hw_features |= NETIF_F_IPV6_CSUM | NETIF_F_TSO6; 86028c2ecf20Sopenharmony_ci 86038c2ecf20Sopenharmony_ci dev->vlan_features = dev->hw_features; 86048c2ecf20Sopenharmony_ci dev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX; 86058c2ecf20Sopenharmony_ci dev->features |= dev->hw_features; 86068c2ecf20Sopenharmony_ci dev->priv_flags |= IFF_UNICAST_FLT; 86078c2ecf20Sopenharmony_ci dev->min_mtu = MIN_ETHERNET_PACKET_SIZE; 86088c2ecf20Sopenharmony_ci dev->max_mtu = MAX_ETHERNET_JUMBO_PACKET_SIZE; 86098c2ecf20Sopenharmony_ci 86108c2ecf20Sopenharmony_ci if (!(bp->flags & BNX2_FLAG_CAN_KEEP_VLAN)) 86118c2ecf20Sopenharmony_ci dev->hw_features &= ~NETIF_F_HW_VLAN_CTAG_RX; 86128c2ecf20Sopenharmony_ci 86138c2ecf20Sopenharmony_ci if ((rc = register_netdev(dev))) { 86148c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Cannot register net device\n"); 86158c2ecf20Sopenharmony_ci goto error; 86168c2ecf20Sopenharmony_ci } 86178c2ecf20Sopenharmony_ci 86188c2ecf20Sopenharmony_ci netdev_info(dev, "%s (%c%d) %s found at mem %lx, IRQ %d, " 86198c2ecf20Sopenharmony_ci "node addr %pM\n", board_info[ent->driver_data].name, 86208c2ecf20Sopenharmony_ci ((BNX2_CHIP_ID(bp) & 0xf000) >> 12) + 'A', 86218c2ecf20Sopenharmony_ci ((BNX2_CHIP_ID(bp) & 0x0ff0) >> 4), 86228c2ecf20Sopenharmony_ci bnx2_bus_string(bp, str), (long)pci_resource_start(pdev, 0), 86238c2ecf20Sopenharmony_ci pdev->irq, dev->dev_addr); 86248c2ecf20Sopenharmony_ci 86258c2ecf20Sopenharmony_ci return 0; 86268c2ecf20Sopenharmony_ci 86278c2ecf20Sopenharmony_cierror: 86288c2ecf20Sopenharmony_ci pci_iounmap(pdev, bp->regview); 86298c2ecf20Sopenharmony_ci pci_release_regions(pdev); 86308c2ecf20Sopenharmony_ci pci_disable_device(pdev); 86318c2ecf20Sopenharmony_cierr_free: 86328c2ecf20Sopenharmony_ci bnx2_free_stats_blk(dev); 86338c2ecf20Sopenharmony_ci free_netdev(dev); 86348c2ecf20Sopenharmony_ci return rc; 86358c2ecf20Sopenharmony_ci} 86368c2ecf20Sopenharmony_ci 86378c2ecf20Sopenharmony_cistatic void 86388c2ecf20Sopenharmony_cibnx2_remove_one(struct pci_dev *pdev) 86398c2ecf20Sopenharmony_ci{ 86408c2ecf20Sopenharmony_ci struct net_device *dev = pci_get_drvdata(pdev); 86418c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 86428c2ecf20Sopenharmony_ci 86438c2ecf20Sopenharmony_ci unregister_netdev(dev); 86448c2ecf20Sopenharmony_ci 86458c2ecf20Sopenharmony_ci del_timer_sync(&bp->timer); 86468c2ecf20Sopenharmony_ci cancel_work_sync(&bp->reset_task); 86478c2ecf20Sopenharmony_ci 86488c2ecf20Sopenharmony_ci pci_iounmap(bp->pdev, bp->regview); 86498c2ecf20Sopenharmony_ci 86508c2ecf20Sopenharmony_ci bnx2_free_stats_blk(dev); 86518c2ecf20Sopenharmony_ci kfree(bp->temp_stats_blk); 86528c2ecf20Sopenharmony_ci 86538c2ecf20Sopenharmony_ci if (bp->flags & BNX2_FLAG_AER_ENABLED) { 86548c2ecf20Sopenharmony_ci pci_disable_pcie_error_reporting(pdev); 86558c2ecf20Sopenharmony_ci bp->flags &= ~BNX2_FLAG_AER_ENABLED; 86568c2ecf20Sopenharmony_ci } 86578c2ecf20Sopenharmony_ci 86588c2ecf20Sopenharmony_ci bnx2_release_firmware(bp); 86598c2ecf20Sopenharmony_ci 86608c2ecf20Sopenharmony_ci free_netdev(dev); 86618c2ecf20Sopenharmony_ci 86628c2ecf20Sopenharmony_ci pci_release_regions(pdev); 86638c2ecf20Sopenharmony_ci pci_disable_device(pdev); 86648c2ecf20Sopenharmony_ci} 86658c2ecf20Sopenharmony_ci 86668c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 86678c2ecf20Sopenharmony_cistatic int 86688c2ecf20Sopenharmony_cibnx2_suspend(struct device *device) 86698c2ecf20Sopenharmony_ci{ 86708c2ecf20Sopenharmony_ci struct net_device *dev = dev_get_drvdata(device); 86718c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 86728c2ecf20Sopenharmony_ci 86738c2ecf20Sopenharmony_ci if (netif_running(dev)) { 86748c2ecf20Sopenharmony_ci cancel_work_sync(&bp->reset_task); 86758c2ecf20Sopenharmony_ci bnx2_netif_stop(bp, true); 86768c2ecf20Sopenharmony_ci netif_device_detach(dev); 86778c2ecf20Sopenharmony_ci del_timer_sync(&bp->timer); 86788c2ecf20Sopenharmony_ci bnx2_shutdown_chip(bp); 86798c2ecf20Sopenharmony_ci __bnx2_free_irq(bp); 86808c2ecf20Sopenharmony_ci bnx2_free_skbs(bp); 86818c2ecf20Sopenharmony_ci } 86828c2ecf20Sopenharmony_ci bnx2_setup_wol(bp); 86838c2ecf20Sopenharmony_ci return 0; 86848c2ecf20Sopenharmony_ci} 86858c2ecf20Sopenharmony_ci 86868c2ecf20Sopenharmony_cistatic int 86878c2ecf20Sopenharmony_cibnx2_resume(struct device *device) 86888c2ecf20Sopenharmony_ci{ 86898c2ecf20Sopenharmony_ci struct net_device *dev = dev_get_drvdata(device); 86908c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 86918c2ecf20Sopenharmony_ci 86928c2ecf20Sopenharmony_ci if (!netif_running(dev)) 86938c2ecf20Sopenharmony_ci return 0; 86948c2ecf20Sopenharmony_ci 86958c2ecf20Sopenharmony_ci bnx2_set_power_state(bp, PCI_D0); 86968c2ecf20Sopenharmony_ci netif_device_attach(dev); 86978c2ecf20Sopenharmony_ci bnx2_request_irq(bp); 86988c2ecf20Sopenharmony_ci bnx2_init_nic(bp, 1); 86998c2ecf20Sopenharmony_ci bnx2_netif_start(bp, true); 87008c2ecf20Sopenharmony_ci return 0; 87018c2ecf20Sopenharmony_ci} 87028c2ecf20Sopenharmony_ci 87038c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(bnx2_pm_ops, bnx2_suspend, bnx2_resume); 87048c2ecf20Sopenharmony_ci#define BNX2_PM_OPS (&bnx2_pm_ops) 87058c2ecf20Sopenharmony_ci 87068c2ecf20Sopenharmony_ci#else 87078c2ecf20Sopenharmony_ci 87088c2ecf20Sopenharmony_ci#define BNX2_PM_OPS NULL 87098c2ecf20Sopenharmony_ci 87108c2ecf20Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */ 87118c2ecf20Sopenharmony_ci/** 87128c2ecf20Sopenharmony_ci * bnx2_io_error_detected - called when PCI error is detected 87138c2ecf20Sopenharmony_ci * @pdev: Pointer to PCI device 87148c2ecf20Sopenharmony_ci * @state: The current pci connection state 87158c2ecf20Sopenharmony_ci * 87168c2ecf20Sopenharmony_ci * This function is called after a PCI bus error affecting 87178c2ecf20Sopenharmony_ci * this device has been detected. 87188c2ecf20Sopenharmony_ci */ 87198c2ecf20Sopenharmony_cistatic pci_ers_result_t bnx2_io_error_detected(struct pci_dev *pdev, 87208c2ecf20Sopenharmony_ci pci_channel_state_t state) 87218c2ecf20Sopenharmony_ci{ 87228c2ecf20Sopenharmony_ci struct net_device *dev = pci_get_drvdata(pdev); 87238c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 87248c2ecf20Sopenharmony_ci 87258c2ecf20Sopenharmony_ci rtnl_lock(); 87268c2ecf20Sopenharmony_ci netif_device_detach(dev); 87278c2ecf20Sopenharmony_ci 87288c2ecf20Sopenharmony_ci if (state == pci_channel_io_perm_failure) { 87298c2ecf20Sopenharmony_ci rtnl_unlock(); 87308c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_DISCONNECT; 87318c2ecf20Sopenharmony_ci } 87328c2ecf20Sopenharmony_ci 87338c2ecf20Sopenharmony_ci if (netif_running(dev)) { 87348c2ecf20Sopenharmony_ci bnx2_netif_stop(bp, true); 87358c2ecf20Sopenharmony_ci del_timer_sync(&bp->timer); 87368c2ecf20Sopenharmony_ci bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET); 87378c2ecf20Sopenharmony_ci } 87388c2ecf20Sopenharmony_ci 87398c2ecf20Sopenharmony_ci pci_disable_device(pdev); 87408c2ecf20Sopenharmony_ci rtnl_unlock(); 87418c2ecf20Sopenharmony_ci 87428c2ecf20Sopenharmony_ci /* Request a slot slot reset. */ 87438c2ecf20Sopenharmony_ci return PCI_ERS_RESULT_NEED_RESET; 87448c2ecf20Sopenharmony_ci} 87458c2ecf20Sopenharmony_ci 87468c2ecf20Sopenharmony_ci/** 87478c2ecf20Sopenharmony_ci * bnx2_io_slot_reset - called after the pci bus has been reset. 87488c2ecf20Sopenharmony_ci * @pdev: Pointer to PCI device 87498c2ecf20Sopenharmony_ci * 87508c2ecf20Sopenharmony_ci * Restart the card from scratch, as if from a cold-boot. 87518c2ecf20Sopenharmony_ci */ 87528c2ecf20Sopenharmony_cistatic pci_ers_result_t bnx2_io_slot_reset(struct pci_dev *pdev) 87538c2ecf20Sopenharmony_ci{ 87548c2ecf20Sopenharmony_ci struct net_device *dev = pci_get_drvdata(pdev); 87558c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 87568c2ecf20Sopenharmony_ci pci_ers_result_t result = PCI_ERS_RESULT_DISCONNECT; 87578c2ecf20Sopenharmony_ci int err = 0; 87588c2ecf20Sopenharmony_ci 87598c2ecf20Sopenharmony_ci rtnl_lock(); 87608c2ecf20Sopenharmony_ci if (pci_enable_device(pdev)) { 87618c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 87628c2ecf20Sopenharmony_ci "Cannot re-enable PCI device after reset\n"); 87638c2ecf20Sopenharmony_ci } else { 87648c2ecf20Sopenharmony_ci pci_set_master(pdev); 87658c2ecf20Sopenharmony_ci pci_restore_state(pdev); 87668c2ecf20Sopenharmony_ci pci_save_state(pdev); 87678c2ecf20Sopenharmony_ci 87688c2ecf20Sopenharmony_ci if (netif_running(dev)) 87698c2ecf20Sopenharmony_ci err = bnx2_init_nic(bp, 1); 87708c2ecf20Sopenharmony_ci 87718c2ecf20Sopenharmony_ci if (!err) 87728c2ecf20Sopenharmony_ci result = PCI_ERS_RESULT_RECOVERED; 87738c2ecf20Sopenharmony_ci } 87748c2ecf20Sopenharmony_ci 87758c2ecf20Sopenharmony_ci if (result != PCI_ERS_RESULT_RECOVERED && netif_running(dev)) { 87768c2ecf20Sopenharmony_ci bnx2_napi_enable(bp); 87778c2ecf20Sopenharmony_ci dev_close(dev); 87788c2ecf20Sopenharmony_ci } 87798c2ecf20Sopenharmony_ci rtnl_unlock(); 87808c2ecf20Sopenharmony_ci 87818c2ecf20Sopenharmony_ci if (!(bp->flags & BNX2_FLAG_AER_ENABLED)) 87828c2ecf20Sopenharmony_ci return result; 87838c2ecf20Sopenharmony_ci 87848c2ecf20Sopenharmony_ci return result; 87858c2ecf20Sopenharmony_ci} 87868c2ecf20Sopenharmony_ci 87878c2ecf20Sopenharmony_ci/** 87888c2ecf20Sopenharmony_ci * bnx2_io_resume - called when traffic can start flowing again. 87898c2ecf20Sopenharmony_ci * @pdev: Pointer to PCI device 87908c2ecf20Sopenharmony_ci * 87918c2ecf20Sopenharmony_ci * This callback is called when the error recovery driver tells us that 87928c2ecf20Sopenharmony_ci * its OK to resume normal operation. 87938c2ecf20Sopenharmony_ci */ 87948c2ecf20Sopenharmony_cistatic void bnx2_io_resume(struct pci_dev *pdev) 87958c2ecf20Sopenharmony_ci{ 87968c2ecf20Sopenharmony_ci struct net_device *dev = pci_get_drvdata(pdev); 87978c2ecf20Sopenharmony_ci struct bnx2 *bp = netdev_priv(dev); 87988c2ecf20Sopenharmony_ci 87998c2ecf20Sopenharmony_ci rtnl_lock(); 88008c2ecf20Sopenharmony_ci if (netif_running(dev)) 88018c2ecf20Sopenharmony_ci bnx2_netif_start(bp, true); 88028c2ecf20Sopenharmony_ci 88038c2ecf20Sopenharmony_ci netif_device_attach(dev); 88048c2ecf20Sopenharmony_ci rtnl_unlock(); 88058c2ecf20Sopenharmony_ci} 88068c2ecf20Sopenharmony_ci 88078c2ecf20Sopenharmony_cistatic void bnx2_shutdown(struct pci_dev *pdev) 88088c2ecf20Sopenharmony_ci{ 88098c2ecf20Sopenharmony_ci struct net_device *dev = pci_get_drvdata(pdev); 88108c2ecf20Sopenharmony_ci struct bnx2 *bp; 88118c2ecf20Sopenharmony_ci 88128c2ecf20Sopenharmony_ci if (!dev) 88138c2ecf20Sopenharmony_ci return; 88148c2ecf20Sopenharmony_ci 88158c2ecf20Sopenharmony_ci bp = netdev_priv(dev); 88168c2ecf20Sopenharmony_ci if (!bp) 88178c2ecf20Sopenharmony_ci return; 88188c2ecf20Sopenharmony_ci 88198c2ecf20Sopenharmony_ci rtnl_lock(); 88208c2ecf20Sopenharmony_ci if (netif_running(dev)) 88218c2ecf20Sopenharmony_ci dev_close(bp->dev); 88228c2ecf20Sopenharmony_ci 88238c2ecf20Sopenharmony_ci if (system_state == SYSTEM_POWER_OFF) 88248c2ecf20Sopenharmony_ci bnx2_set_power_state(bp, PCI_D3hot); 88258c2ecf20Sopenharmony_ci 88268c2ecf20Sopenharmony_ci rtnl_unlock(); 88278c2ecf20Sopenharmony_ci} 88288c2ecf20Sopenharmony_ci 88298c2ecf20Sopenharmony_cistatic const struct pci_error_handlers bnx2_err_handler = { 88308c2ecf20Sopenharmony_ci .error_detected = bnx2_io_error_detected, 88318c2ecf20Sopenharmony_ci .slot_reset = bnx2_io_slot_reset, 88328c2ecf20Sopenharmony_ci .resume = bnx2_io_resume, 88338c2ecf20Sopenharmony_ci}; 88348c2ecf20Sopenharmony_ci 88358c2ecf20Sopenharmony_cistatic struct pci_driver bnx2_pci_driver = { 88368c2ecf20Sopenharmony_ci .name = DRV_MODULE_NAME, 88378c2ecf20Sopenharmony_ci .id_table = bnx2_pci_tbl, 88388c2ecf20Sopenharmony_ci .probe = bnx2_init_one, 88398c2ecf20Sopenharmony_ci .remove = bnx2_remove_one, 88408c2ecf20Sopenharmony_ci .driver.pm = BNX2_PM_OPS, 88418c2ecf20Sopenharmony_ci .err_handler = &bnx2_err_handler, 88428c2ecf20Sopenharmony_ci .shutdown = bnx2_shutdown, 88438c2ecf20Sopenharmony_ci}; 88448c2ecf20Sopenharmony_ci 88458c2ecf20Sopenharmony_cimodule_pci_driver(bnx2_pci_driver); 8846