📄 e1000_ethtool.c
字号:
regs_buff[25] = regs_buff[24]; /* phy remote receiver status */ if (hw->mac.type >= e1000_82540 && hw->phy.media_type == e1000_media_type_copper) { regs_buff[26] = E1000_READ_REG(hw, E1000_MANC); }}static int e1000_get_eeprom_len(struct net_device *netdev){ struct e1000_adapter *adapter = netdev_priv(netdev); return adapter->hw.nvm.word_size * 2;}static int e1000_get_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, u8 *bytes){ struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; u16 *eeprom_buff; int first_word, last_word; int ret_val = 0; u16 i; if (eeprom->len == 0) return -EINVAL; eeprom->magic = hw->vendor_id | (hw->device_id << 16); first_word = eeprom->offset >> 1; last_word = (eeprom->offset + eeprom->len - 1) >> 1; eeprom_buff = kmalloc(sizeof(u16) * (last_word - first_word + 1), GFP_KERNEL); if (!eeprom_buff) return -ENOMEM; if (hw->nvm.type == e1000_nvm_eeprom_spi) ret_val = e1000_read_nvm(hw, first_word, last_word - first_word + 1, eeprom_buff); else { for (i = 0; i < last_word - first_word + 1; i++) if ((ret_val = e1000_read_nvm(hw, first_word + i, 1, &eeprom_buff[i]))) break; } /* Device's eeprom is always little-endian, word addressable */ for (i = 0; i < last_word - first_word + 1; i++) le16_to_cpus(&eeprom_buff[i]); memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len); kfree(eeprom_buff); return ret_val;}static int e1000_set_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, u8 *bytes){ struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; u16 *eeprom_buff; void *ptr; int max_len, first_word, last_word, ret_val = 0; u16 i; if (eeprom->len == 0) return -EOPNOTSUPP; if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16))) return -EFAULT; max_len = hw->nvm.word_size * 2; first_word = eeprom->offset >> 1; last_word = (eeprom->offset + eeprom->len - 1) >> 1; eeprom_buff = kmalloc(max_len, GFP_KERNEL); if (!eeprom_buff) return -ENOMEM; ptr = (void *)eeprom_buff; if (eeprom->offset & 1) { /* need read/modify/write of first changed EEPROM word */ /* only the second byte of the word is being modified */ ret_val = e1000_read_nvm(hw, first_word, 1, &eeprom_buff[0]); ptr++; } if (((eeprom->offset + eeprom->len) & 1) && (ret_val == 0)) { /* need read/modify/write of last changed EEPROM word */ /* only the first byte of the word is being modified */ ret_val = e1000_read_nvm(hw, last_word, 1, &eeprom_buff[last_word - first_word]); } /* Device's eeprom is always little-endian, word addressable */ for (i = 0; i < last_word - first_word + 1; i++) le16_to_cpus(&eeprom_buff[i]); memcpy(ptr, bytes, eeprom->len); for (i = 0; i < last_word - first_word + 1; i++) eeprom_buff[i] = cpu_to_le16(eeprom_buff[i]); ret_val = e1000_write_nvm(hw, first_word, last_word - first_word + 1, eeprom_buff); /* Update the checksum over the first part of the EEPROM if needed */ if ((ret_val == 0) && (first_word <= NVM_CHECKSUM_REG)) e1000_update_nvm_checksum(hw); kfree(eeprom_buff); return ret_val;}static void e1000_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo){ struct e1000_adapter *adapter = netdev_priv(netdev); strncpy(drvinfo->driver, e1000_driver_name, 32); strncpy(drvinfo->version, e1000_driver_version, 32); strcpy(drvinfo->fw_version, "N/A"); strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); drvinfo->n_stats = E1000_STATS_LEN; drvinfo->testinfo_len = E1000_TEST_LEN; drvinfo->regdump_len = e1000_get_regs_len(netdev); drvinfo->eedump_len = e1000_get_eeprom_len(netdev);}static void e1000_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring){ struct e1000_adapter *adapter = netdev_priv(netdev); e1000_mac_type mac_type = adapter->hw.mac.type; struct e1000_tx_ring *tx_ring = adapter->tx_ring; struct e1000_rx_ring *rx_ring = adapter->rx_ring; ring->rx_max_pending = (mac_type < e1000_82544) ? E1000_MAX_RXD : E1000_MAX_82544_RXD; ring->tx_max_pending = (mac_type < e1000_82544) ? E1000_MAX_TXD : E1000_MAX_82544_TXD; ring->rx_mini_max_pending = 0; ring->rx_jumbo_max_pending = 0; ring->rx_pending = rx_ring->count; ring->tx_pending = tx_ring->count; ring->rx_mini_pending = 0; ring->rx_jumbo_pending = 0;}static int e1000_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring){ struct e1000_adapter *adapter = netdev_priv(netdev); e1000_mac_type mac_type = adapter->hw.mac.type; struct e1000_tx_ring *tx_ring, *tx_old; struct e1000_rx_ring *rx_ring, *rx_old; int i, err, tx_ring_size, rx_ring_size; if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) return -EINVAL; tx_ring_size = sizeof(struct e1000_tx_ring) * adapter->num_tx_queues; rx_ring_size = sizeof(struct e1000_rx_ring) * adapter->num_rx_queues; while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) msleep(1); if (netif_running(adapter->netdev)) e1000_down(adapter); tx_old = adapter->tx_ring; rx_old = adapter->rx_ring; err = -ENOMEM; tx_ring = kzalloc(tx_ring_size, GFP_KERNEL); if (!tx_ring) goto err_alloc_tx; /* use a memcpy to save any previously configured * items like napi structs from having to be * reinitialized */ memcpy(tx_ring, tx_old, tx_ring_size); rx_ring = kzalloc(rx_ring_size, GFP_KERNEL); if (!rx_ring) goto err_alloc_rx; memcpy(rx_ring, rx_old, rx_ring_size); adapter->tx_ring = tx_ring; adapter->rx_ring = rx_ring; rx_ring->count = max(ring->rx_pending,(u32)E1000_MIN_RXD); rx_ring->count = min(rx_ring->count,(u32)(mac_type < e1000_82544 ? E1000_MAX_RXD : E1000_MAX_82544_RXD)); rx_ring->count = ALIGN(rx_ring->count, REQ_RX_DESCRIPTOR_MULTIPLE); tx_ring->count = max(ring->tx_pending,(u32)E1000_MIN_TXD); tx_ring->count = min(tx_ring->count,(u32)(mac_type < e1000_82544 ? E1000_MAX_TXD : E1000_MAX_82544_TXD)); tx_ring->count = ALIGN(tx_ring->count, REQ_TX_DESCRIPTOR_MULTIPLE); /* overwrite the counts with the new values */ for (i = 0; i < adapter->num_tx_queues; i++) tx_ring[i].count = tx_ring->count; for (i = 0; i < adapter->num_rx_queues; i++) rx_ring[i].count = rx_ring->count; if (netif_running(adapter->netdev)) { /* Try to get new resources before deleting old */ if ((err = e1000_setup_all_rx_resources(adapter))) goto err_setup_rx; if ((err = e1000_setup_all_tx_resources(adapter))) goto err_setup_tx; /* restore the old in order to free it, * then add in the new */ adapter->rx_ring = rx_old; adapter->tx_ring = tx_old; e1000_free_all_rx_resources(adapter); e1000_free_all_tx_resources(adapter); kfree(tx_old); kfree(rx_old); adapter->rx_ring = rx_ring; adapter->tx_ring = tx_ring; if ((err = e1000_up(adapter))) goto err_setup; } clear_bit(__E1000_RESETTING, &adapter->state); return 0;err_setup_tx: e1000_free_all_rx_resources(adapter);err_setup_rx: adapter->rx_ring = rx_old; adapter->tx_ring = tx_old; kfree(rx_ring);err_alloc_rx: kfree(tx_ring);err_alloc_tx: e1000_up(adapter);err_setup: clear_bit(__E1000_RESETTING, &adapter->state); return err;}static bool reg_pattern_test(struct e1000_adapter *adapter, u64 *data, int reg, int offset, u32 mask, u32 write){ \ u32 pat, val; static const u32 test[] = {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; for (pat = 0; pat < ARRAY_SIZE(test); pat++) { E1000_WRITE_REG_ARRAY(&adapter->hw, reg, offset, (test[pat] & write)); val = E1000_READ_REG_ARRAY(&adapter->hw, reg, offset); if (val != (test[pat] & write & mask)) { DPRINTK(DRV, ERR, "pattern test reg %04X failed: got " "0x%08X expected 0x%08X\n", E1000_REGISTER(&adapter->hw, reg) + offset, val, (test[pat] & write & mask)); *data = E1000_REGISTER(&adapter->hw, reg); return 1; } } return 0;}static bool reg_set_and_check(struct e1000_adapter *adapter, u64 *data, int reg, u32 mask, u32 write){ u32 val; E1000_WRITE_REG(&adapter->hw, reg, write & mask); val = E1000_READ_REG(&adapter->hw, reg); if ((write & mask) != (val & mask)) { DPRINTK(DRV, ERR, "set/check reg %04X test failed: got 0x%08X" "expected 0x%08X\n", reg, (val & mask), (write & mask)); *data = E1000_REGISTER(&adapter->hw, reg); return 1; } return 0;}#define REG_PATTERN_TEST_ARRAY(reg, offset, mask, write) \ do { \ if (reg_pattern_test(adapter, data, reg, offset, mask, write)) \ return 1; \ } while (0)#define REG_PATTERN_TEST(reg, mask, write) \ REG_PATTERN_TEST_ARRAY(reg, 0, mask, write)#define REG_SET_AND_CHECK(reg, mask, write) \ do { \ if (reg_set_and_check(adapter, data, reg, mask, write)) \ return 1; \ } while (0)static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data){ struct e1000_mac_info *mac = &adapter->hw.mac; u32 value, before, after; u32 i, toggle; /* The status register is Read Only, so a write should fail. * Some bits that get toggled are ignored. */ toggle = 0xFFFFF833; before = E1000_READ_REG(&adapter->hw, E1000_STATUS); value = (E1000_READ_REG(&adapter->hw, E1000_STATUS) & toggle); E1000_WRITE_REG(&adapter->hw, E1000_STATUS, toggle); after = E1000_READ_REG(&adapter->hw, E1000_STATUS) & toggle; if (value != after) { DPRINTK(DRV, ERR, "failed STATUS register test got: " "0x%08X expected: 0x%08X\n", after, value); *data = 1; return 1; } /* restore previous status */ E1000_WRITE_REG(&adapter->hw, E1000_STATUS, before); REG_PATTERN_TEST(E1000_FCAL, 0xFFFFFFFF, 0xFFFFFFFF); REG_PATTERN_TEST(E1000_FCAH, 0x0000FFFF, 0xFFFFFFFF); REG_PATTERN_TEST(E1000_FCT, 0x0000FFFF, 0xFFFFFFFF); REG_PATTERN_TEST(E1000_VET, 0x0000FFFF, 0xFFFFFFFF); REG_PATTERN_TEST(E1000_RDTR, 0x0000FFFF, 0xFFFFFFFF); REG_PATTERN_TEST(E1000_RDBAH(0), 0xFFFFFFFF, 0xFFFFFFFF); REG_PATTERN_TEST(E1000_RDLEN(0), 0x000FFF80, 0x000FFFFF); REG_PATTERN_TEST(E1000_RDH(0), 0x0000FFFF, 0x0000FFFF); REG_PATTERN_TEST(E1000_RDT(0), 0x0000FFFF, 0x0000FFFF); REG_PATTERN_TEST(E1000_FCRTH, 0x0000FFF8, 0x0000FFF8); REG_PATTERN_TEST(E1000_FCTTV, 0x0000FFFF, 0x0000FFFF); REG_PATTERN_TEST(E1000_TIPG, 0x3FFFFFFF, 0x3FFFFFFF); REG_PATTERN_TEST(E1000_TDBAH(0), 0xFFFFFFFF, 0xFFFFFFFF); REG_PATTERN_TEST(E1000_TDLEN(0), 0x000FFF80, 0x000FFFFF); REG_SET_AND_CHECK(E1000_RCTL, 0xFFFFFFFF, 0x00000000); before = 0x06DFB3FE; REG_SET_AND_CHECK(E1000_RCTL, before, 0x003FFFFB); REG_SET_AND_CHECK(E1000_TCTL, 0xFFFFFFFF, 0x00000000); if (mac->type >= e1000_82543) { REG_SET_AND_CHECK(E1000_RCTL, before, 0xFFFFFFFF); REG_PATTERN_TEST(E1000_RDBAL(0), 0xFFFFFFF0, 0xFFFFFFFF); REG_PATTERN_TEST(E1000_TXCW, 0xC000FFFF, 0x0000FFFF); REG_PATTERN_TEST(E1000_TDBAL(0), 0xFFFFFFF0, 0xFFFFFFFF); REG_PATTERN_TEST(E1000_TIDV, 0x0000FFFF, 0x0000FFFF); for (i = 0; i < mac->rar_entry_count; i++) { REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1), 0x8003FFFF, 0xFFFFFFFF); } } else { REG_SET_AND_CHECK(E1000_RCTL, 0xFFFFFFFF, 0x01FFFFFF); REG_PATTERN_TEST(E1000_RDBAL(0), 0xFFFFF000, 0xFFFFFFFF); REG_PATTERN_TEST(E1000_TXCW, 0x0000FFFF, 0x0000FFFF); REG_PATTERN_TEST(E1000_TDBAL(0), 0xFFFFF000, 0xFFFFFFFF); } for (i = 0; i < mac->mta_reg_count; i++) REG_PATTERN_TEST_ARRAY(E1000_MTA, i, 0xFFFFFFFF, 0xFFFFFFFF); *data = 0; return 0;}static int e1000_eeprom_test(struct e1000_adapter *adapter, u64 *data){ u16 temp; u16 checksum = 0; u16 i; *data = 0; /* Read and add up the contents of the EEPROM */ for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) { if ((e1000_read_nvm(&adapter->hw, i, 1, &temp)) < 0) { *data = 1; break; } checksum += temp; } /* If Checksum is not Correct return error else test passed */ if ((checksum != (u16) NVM_SUM) && !(*data)) *data = 2; return *data;}static irqreturn_t e1000_test_intr(int irq, void *data){ struct net_device *netdev = (struct net_device *) data; struct e1000_adapter *adapter = netdev_priv(netdev); adapter->test_icr |= E1000_READ_REG(&adapter->hw, E1000_ICR); return IRQ_HANDLED;}static int e1000_intr_test(struct e1000_adapter *adapter, u64 *data){ struct net_device *netdev = adapter->netdev; u32 mask, i=0, shared_int = TRUE; u32 irq = adapter->pdev->irq; *data = 0; /* NOTE: we don't test MSI interrupts here, yet */ /* Hook up test interrupt handler just for this test */ if (!request_irq(irq, &e1000_test_intr, IRQF_PROBE_SHARED, netdev->name, netdev)) shared_int = FALSE; else if (request_irq(irq, &e1000_test_intr, IRQF_SHARED, netdev->name, netdev)) { *data = 1; return -1; } DPRINTK(HW, INFO, "testing %s interrupt\n", (shared_int ? "shared" : "unshared")); /* Disable all the interrupts */ E1000_WRITE_REG(&adapter->hw, E1000_IMC, 0xFFFFFFFF); msleep(10); /* Test each interrupt */ for (; i < 10; i++) { /* Interrupt to test */ mask = 1 << i; if (!shared_int) { /* Disable the interrupt to be reported in * the cause register and then force the same * interrupt and see if one gets posted. If * an interrupt was posted to the bus, the * test failed. */ adapter->test_icr = 0; E1000_WRITE_REG(&adapter->hw, E1000_IMC, mask); E1000_WRITE_REG(&adapter->hw, E1000_ICS, mask); msleep(10); if (adapter->test_icr & mask) { *data = 3; break; } } /* Enable the interrupt to be reported in * the cause register and then force the same * interrupt and see if one gets posted. If * an interrupt was not posted to the bus, the * test failed. */ adapter->test_icr = 0; E1000_WRITE_REG(&adapter->hw, E1000_IMS, mask); E1000_WRITE_REG(&adapter->hw, E1000_ICS, mask); msleep(10); if (!(adapter->test_icr & mask)) { *data = 4; break; } if (!shared_int) { /* Disable the other interrupts to be reported in * the cause register and then force the other * interrupts and see if any get posted. If * an interrupt was posted to the bus, the * test failed. */ adapter->test_icr = 0; E1000_WRITE_REG(&adapter->hw, E1000_IMC, ~mask & 0x00007FFF); E1000_WRITE_REG(&adapter->hw, E1000_ICS, ~mask & 0x00007FFF); msleep(10); if (adapter->test_icr) { *data = 5; break; } } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -