📄 e1000_ethtool.c
字号:
uint16_t *eeprom_buff; int first_word, last_word; int ret_val = 0; uint16_t 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(uint16_t) * (last_word - first_word + 1), GFP_KERNEL); if (!eeprom_buff) return -ENOMEM; if (hw->eeprom.type == e1000_eeprom_spi) ret_val = e1000_read_eeprom(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_eeprom(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, (uint8_t *)eeprom_buff + (eeprom->offset & 1), eeprom->len); kfree(eeprom_buff); return ret_val;}static inte1000_set_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, uint8_t *bytes){ struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; uint16_t *eeprom_buff; void *ptr; int max_len, first_word, last_word, ret_val = 0; uint16_t i; if (eeprom->len == 0) return -EOPNOTSUPP; if (eeprom->magic != (hw->vendor_id | (hw->device_id << 16))) return -EFAULT; max_len = hw->eeprom.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_eeprom(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_eeprom(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_eeprom(hw, first_word, last_word - first_word + 1, eeprom_buff); /* Update the checksum over the first part of the EEPROM if needed * and flush shadow RAM for 82573 conrollers */ if ((ret_val == 0) && ((first_word <= EEPROM_CHECKSUM_REG) || (hw->mac_type == e1000_82573))) e1000_update_eeprom_checksum(hw); kfree(eeprom_buff); return ret_val;}static voide1000_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo){ struct e1000_adapter *adapter = netdev_priv(netdev); char firmware_version[32]; uint16_t eeprom_data; strncpy(drvinfo->driver, e1000_driver_name, 32); strncpy(drvinfo->version, e1000_driver_version, 32); /* EEPROM image version # is reported as firmware version # for * 8257{1|2|3} controllers */ e1000_read_eeprom(&adapter->hw, 5, 1, &eeprom_data); switch (adapter->hw.mac_type) { case e1000_82571: case e1000_82572: case e1000_82573: case e1000_80003es2lan: case e1000_ich8lan: sprintf(firmware_version, "%d.%d-%d", (eeprom_data & 0xF000) >> 12, (eeprom_data & 0x0FF0) >> 4, eeprom_data & 0x000F); break; default: sprintf(firmware_version, "N/A"); } strncpy(drvinfo->fw_version, firmware_version, 32); 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 voide1000_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 *txdr = adapter->tx_ring; struct e1000_rx_ring *rxdr = 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 = rxdr->count; ring->tx_pending = txdr->count; ring->rx_mini_pending = 0; ring->rx_jumbo_pending = 0;}static inte1000_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 *txdr, *tx_old, *tx_new; struct e1000_rx_ring *rxdr, *rx_old, *rx_new; 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->flags)) msleep(1); if (netif_running(adapter->netdev)) e1000_down(adapter); tx_old = adapter->tx_ring; rx_old = adapter->rx_ring; adapter->tx_ring = kmalloc(tx_ring_size, GFP_KERNEL); if (!adapter->tx_ring) { err = -ENOMEM; goto err_setup_rx; } memset(adapter->tx_ring, 0, tx_ring_size); adapter->rx_ring = kmalloc(rx_ring_size, GFP_KERNEL); if (!adapter->rx_ring) { kfree(adapter->tx_ring); err = -ENOMEM; goto err_setup_rx; } memset(adapter->rx_ring, 0, rx_ring_size); txdr = adapter->tx_ring; rxdr = adapter->rx_ring; rxdr->count = max(ring->rx_pending,(uint32_t)E1000_MIN_RXD); rxdr->count = min(rxdr->count,(uint32_t)(mac_type < e1000_82544 ? E1000_MAX_RXD : E1000_MAX_82544_RXD)); E1000_ROUNDUP(rxdr->count, REQ_RX_DESCRIPTOR_MULTIPLE); txdr->count = max(ring->tx_pending,(uint32_t)E1000_MIN_TXD); txdr->count = min(txdr->count,(uint32_t)(mac_type < e1000_82544 ? E1000_MAX_TXD : E1000_MAX_82544_TXD)); E1000_ROUNDUP(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE); for (i = 0; i < adapter->num_tx_queues; i++) txdr[i].count = txdr->count; for (i = 0; i < adapter->num_rx_queues; i++) rxdr[i].count = rxdr->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; /* save the new, restore the old in order to free it, * then restore the new back again */ rx_new = adapter->rx_ring; tx_new = adapter->tx_ring; 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_new; adapter->tx_ring = tx_new; if ((err = e1000_up(adapter))) goto err_setup; } clear_bit(__E1000_RESETTING, &adapter->flags); return 0;err_setup_tx: e1000_free_all_rx_resources(adapter);err_setup_rx: adapter->rx_ring = rx_old; adapter->tx_ring = tx_old; e1000_up(adapter);err_setup: clear_bit(__E1000_RESETTING, &adapter->flags); return err;}#define REG_PATTERN_TEST(R, M, W) \{ \ uint32_t pat, value; \ uint32_t test[] = \ {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; \ for (pat = 0; pat < sizeof(test)/sizeof(test[0]); pat++) { \ E1000_WRITE_REG(&adapter->hw, R, (test[pat] & W)); \ value = E1000_READ_REG(&adapter->hw, R); \ if (value != (test[pat] & W & M)) { \ DPRINTK(DRV, ERR, "pattern test reg %04X failed: got " \ "0x%08X expected 0x%08X\n", \ E1000_##R, value, (test[pat] & W & M)); \ *data = (adapter->hw.mac_type < e1000_82543) ? \ E1000_82542_##R : E1000_##R; \ return 1; \ } \ } \}#define REG_SET_AND_CHECK(R, M, W) \{ \ uint32_t value; \ E1000_WRITE_REG(&adapter->hw, R, W & M); \ value = E1000_READ_REG(&adapter->hw, R); \ if ((W & M) != (value & M)) { \ DPRINTK(DRV, ERR, "set/check reg %04X test failed: got 0x%08X "\ "expected 0x%08X\n", E1000_##R, (value & M), (W & M)); \ *data = (adapter->hw.mac_type < e1000_82543) ? \ E1000_82542_##R : E1000_##R; \ return 1; \ } \}static inte1000_reg_test(struct e1000_adapter *adapter, uint64_t *data){ uint32_t value, before, after; uint32_t i, toggle; /* The status register is Read Only, so a write should fail. * Some bits that get toggled are ignored. */ switch (adapter->hw.mac_type) { /* there are several bits on newer hardware that are r/w */ case e1000_82571: case e1000_82572: case e1000_80003es2lan: toggle = 0x7FFFF3FF; break; case e1000_82573: case e1000_ich8lan: toggle = 0x7FFFF033; break; default: toggle = 0xFFFFF833; break; } before = E1000_READ_REG(&adapter->hw, STATUS); value = (E1000_READ_REG(&adapter->hw, STATUS) & toggle); E1000_WRITE_REG(&adapter->hw, STATUS, toggle); after = E1000_READ_REG(&adapter->hw, 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, STATUS, before); if (adapter->hw.mac_type != e1000_ich8lan) { REG_PATTERN_TEST(FCAL, 0xFFFFFFFF, 0xFFFFFFFF); REG_PATTERN_TEST(FCAH, 0x0000FFFF, 0xFFFFFFFF); REG_PATTERN_TEST(FCT, 0x0000FFFF, 0xFFFFFFFF); REG_PATTERN_TEST(VET, 0x0000FFFF, 0xFFFFFFFF); } REG_PATTERN_TEST(RDTR, 0x0000FFFF, 0xFFFFFFFF); REG_PATTERN_TEST(RDBAH, 0xFFFFFFFF, 0xFFFFFFFF); REG_PATTERN_TEST(RDLEN, 0x000FFF80, 0x000FFFFF); REG_PATTERN_TEST(RDH, 0x0000FFFF, 0x0000FFFF); REG_PATTERN_TEST(RDT, 0x0000FFFF, 0x0000FFFF); REG_PATTERN_TEST(FCRTH, 0x0000FFF8, 0x0000FFF8); REG_PATTERN_TEST(FCTTV, 0x0000FFFF, 0x0000FFFF); REG_PATTERN_TEST(TIPG, 0x3FFFFFFF, 0x3FFFFFFF); REG_PATTERN_TEST(TDBAH, 0xFFFFFFFF, 0xFFFFFFFF); REG_PATTERN_TEST(TDLEN, 0x000FFF80, 0x000FFFFF); REG_SET_AND_CHECK(RCTL, 0xFFFFFFFF, 0x00000000); before = (adapter->hw.mac_type == e1000_ich8lan ? 0x06C3B33E : 0x06DFB3FE); REG_SET_AND_CHECK(RCTL, before, 0x003FFFFB); REG_SET_AND_CHECK(TCTL, 0xFFFFFFFF, 0x00000000); if (adapter->hw.mac_type >= e1000_82543) { REG_SET_AND_CHECK(RCTL, before, 0xFFFFFFFF); REG_PATTERN_TEST(RDBAL, 0xFFFFFFF0, 0xFFFFFFFF); if (adapter->hw.mac_type != e1000_ich8lan) REG_PATTERN_TEST(TXCW, 0xC000FFFF, 0x0000FFFF); REG_PATTERN_TEST(TDBAL, 0xFFFFFFF0, 0xFFFFFFFF); REG_PATTERN_TEST(TIDV, 0x0000FFFF, 0x0000FFFF); value = (adapter->hw.mac_type == e1000_ich8lan ? E1000_RAR_ENTRIES_ICH8LAN : E1000_RAR_ENTRIES); for (i = 0; i < value; i++) { REG_PATTERN_TEST(RA + (((i << 1) + 1) << 2), 0x8003FFFF, 0xFFFFFFFF); } } else { REG_SET_AND_CHECK(RCTL, 0xFFFFFFFF, 0x01FFFFFF); REG_PATTERN_TEST(RDBAL, 0xFFFFF000, 0xFFFFFFFF); REG_PATTERN_TEST(TXCW, 0x0000FFFF, 0x0000FFFF); REG_PATTERN_TEST(TDBAL, 0xFFFFF000, 0xFFFFFFFF); } value = (adapter->hw.mac_type == e1000_ich8lan ? E1000_MC_TBL_SIZE_ICH8LAN : E1000_MC_TBL_SIZE); for (i = 0; i < value; i++) REG_PATTERN_TEST(MTA + (i << 2), 0xFFFFFFFF, 0xFFFFFFFF); *data = 0; return 0;}static inte1000_eeprom_test(struct e1000_adapter *adapter, uint64_t *data){ uint16_t temp; uint16_t checksum = 0; uint16_t i; *data = 0; /* Read and add up the contents of the EEPROM */ for (i = 0; i < (EEPROM_CHECKSUM_REG + 1); i++) { if ((e1000_read_eeprom(&adapter->hw, i, 1, &temp)) < 0) { *data = 1; break; } checksum += temp; } /* If Checksum is not Correct return error else test passed */ if ((checksum != (uint16_t) EEPROM_SUM) && !(*data)) *data = 2; return *data;}static irqreturn_te1000_test_intr(int irq, void *data, struct pt_regs *regs){ struct net_device *netdev = (struct net_device *) data; struct e1000_adapter *adapter = netdev_priv(netdev); adapter->test_icr |= E1000_READ_REG(&adapter->hw, ICR); return IRQ_HANDLED;}static inte1000_intr_test(struct e1000_adapter *adapter, uint64_t *data){ struct net_device *netdev = adapter->netdev; uint32_t mask, i=0, shared_int = TRUE; uint32_t 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, IMC, 0xFFFFFFFF); msec_delay(10); /* Test each interrupt */ for (; i < 10; i++) { if (adapter->hw.mac_type == e1000_ich8lan && i == 8) continue; /* 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, IMC, mask); E1000_WRITE_REG(&adapter->hw, ICS, mask); msec_delay(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, IMS, mask); E1000_WRITE_REG(&adapter->hw, ICS, mask); msec_delay(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, IMC, ~mask & 0x00007FFF); E1000_WRITE_REG(&adapter->hw, ICS, ~mask & 0x00007FFF); msec_delay(10); if (adapter->test_icr) { *data = 5;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -