📄 e1000_idiag.c
字号:
/******************************************************************************* Copyright(c) 1999 - 2002 Intel Corporation. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. The full GNU General Public License is included in this distribution in the file called LICENSE. Contact Information: Linux NICS <linux.nics@intel.com> Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497*******************************************************************************//* * Intel PRO diagnostics */#include "e1000.h"#include "idiag_pro.h"#include "idiag_e1000.h"extern int e1000_up(struct e1000_adapter *adapter);extern void e1000_down(struct e1000_adapter *adapter);extern void e1000_reset(struct e1000_adapter *adapter);#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)) { \ param->reg = \ (adapter->hw.mac_type < e1000_82543) ? \ E1000_82542_##R : E1000_##R; \ param->write_value = test[pat] & W; \ param->read_value = value; \ return IDIAG_PRO_STAT_TEST_FAILED; \ } \ } \}#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)) { \ param->reg = (adapter->hw.mac_type < e1000_82543) ? \ E1000_82542_##R : E1000_##R; \ param->write_value = W & M; \ param->read_value = value & M; \ return IDIAG_PRO_STAT_TEST_FAILED; \ } \}static enum idiag_pro_state1000_diag_reg_test(struct e1000_adapter *adapter, uint8_t *diag_param){ struct idiag_e1000_diag_reg_test_param *param = (struct idiag_e1000_diag_reg_test_param *) diag_param; uint32_t value; uint32_t i; /* The status register is Read Only, so a write should fail. * Some bits that get toggled are ignored. */ value = (E1000_READ_REG(&adapter->hw, STATUS) & (0xFFFFF833)); E1000_WRITE_REG(&adapter->hw, STATUS, (0xFFFFFFFF)); if(value != (E1000_READ_REG(&adapter->hw, STATUS) & (0xFFFFF833))) { param->reg = E1000_STATUS; param->write_value = 0xFFFFFFFF; param->read_value = value; return IDIAG_PRO_STAT_TEST_FAILED; } 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); REG_SET_AND_CHECK(RCTL, 0x06DFB3FE, 0x003FFFFB); REG_SET_AND_CHECK(TCTL, 0xFFFFFFFF, 0x00000000); if(adapter->hw.mac_type >= e1000_82543) { REG_SET_AND_CHECK(RCTL, 0x06DFB3FE, 0xFFFFFFFF); REG_PATTERN_TEST(RDBAL, 0xFFFFFFF0, 0xFFFFFFFF); REG_PATTERN_TEST(TXCW, 0xC000FFFF, 0x0000FFFF); REG_PATTERN_TEST(TDBAL, 0xFFFFFFF0, 0xFFFFFFFF); REG_PATTERN_TEST(TIDV, 0x0000FFFF, 0x0000FFFF); for(i = 0; i < E1000_RAR_ENTRIES; i++) { REG_PATTERN_TEST(RA + ((i << 1) << 2), 0xFFFFFFFF, 0xFFFFFFFF); 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); } for(i = 0; i < E1000_MC_TBL_SIZE; i++) REG_PATTERN_TEST(MTA + (i << 2), 0xFFFFFFFF, 0xFFFFFFFF); return IDIAG_PRO_STAT_OK;}static enum idiag_pro_state1000_diag_eeprom_test(struct e1000_adapter *adapter, uint8_t *diag_param){ struct idiag_e1000_diag_eeprom_test_param *param = (struct idiag_e1000_diag_eeprom_test_param *) diag_param; uint16_t temp; uint16_t checksum = 0; uint16_t i; /* 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, &temp)) < 0) { param->actual_checksum = checksum; param->expected_checksum = EEPROM_SUM; return IDIAG_PRO_STAT_TEST_FATAL; } checksum += temp; } /* If Checksum is not Correct return error else test passed */ if(checksum != (uint16_t) EEPROM_SUM) { param->actual_checksum = checksum; param->expected_checksum = EEPROM_SUM; return IDIAG_PRO_STAT_TEST_FAILED; } return IDIAG_PRO_STAT_OK;}static voide1000_diag_intr(int irq, void *data, struct pt_regs *regs){ struct net_device *netdev = (struct net_device *) data; struct e1000_adapter *adapter = netdev->priv; adapter->diag_icr |= E1000_READ_REG(&adapter->hw, ICR); return;}static enum idiag_pro_state1000_diag_intr_test(struct e1000_adapter *adapter, uint8_t *diag_param){ struct net_device *netdev = adapter->netdev; enum idiag_e1000_diag_intr_test_param *param = (enum idiag_e1000_diag_intr_test_param *) diag_param; uint32_t icr, i, mask; *param = IDIAG_E1000_INTR_TEST_OK; /* Hook up diag interrupt handler just for this test */ if(request_irq (netdev->irq, &e1000_diag_intr, SA_SHIRQ, netdev->name, netdev)) return IDIAG_PRO_STAT_TEST_FATAL; /* Disable all the interrupts */ E1000_WRITE_REG(&adapter->hw, IMC, 0xFFFFFFFF); msec_delay(10); /* Interrupts are disabled, so read interrupt cause * register (icr) twice to verify that there are no interrupts * pending. icr is clear on read. */ icr = E1000_READ_REG(&adapter->hw, ICR); icr = E1000_READ_REG(&adapter->hw, ICR); if(icr != 0) { /* if icr is non-zero, there is no point * running other interrupt tests. */ *param = IDIAG_E1000_INTR_TEST_NOT_EXEC; return IDIAG_PRO_STAT_TEST_FAILED; } /* Test each interrupt */ for(i = 0; i < 10; i++) { /* Interrupt to test */ mask = 1 << i; /* 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->diag_icr = 0; E1000_WRITE_REG(&adapter->hw, IMC, mask); E1000_WRITE_REG(&adapter->hw, ICS, mask); msec_delay(10); if(adapter->diag_icr & mask) { *param = IDIAG_E1000_INTR_TEST_FAILED_WHILE_DISABLED; 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->diag_icr = 0; E1000_WRITE_REG(&adapter->hw, IMS, mask); E1000_WRITE_REG(&adapter->hw, ICS, mask); msec_delay(10); if(!(adapter->diag_icr & mask)) { *param = IDIAG_E1000_INTR_TEST_FAILED_WHILE_ENABLED; break; } /* 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->diag_icr = 0; E1000_WRITE_REG(&adapter->hw, IMC, ~mask); E1000_WRITE_REG(&adapter->hw, ICS, ~mask); msec_delay(10); if(adapter->diag_icr) { *param = IDIAG_E1000_INTR_TEST_FAILED_MASKED_ENABLED; break; } } /* Disable all the interrupts */ E1000_WRITE_REG(&adapter->hw, IMC, 0xFFFFFFFF); msec_delay(10); /* Unhook diag interrupt handler */ free_irq(netdev->irq, netdev); return (*param == IDIAG_E1000_INTR_TEST_OK) ? IDIAG_PRO_STAT_OK : IDIAG_PRO_STAT_TEST_FAILED;}static voide1000_free_desc_rings(struct e1000_adapter *adapter){ struct e1000_desc_ring *txdr = &adapter->diag_tx_ring; struct e1000_desc_ring *rxdr = &adapter->diag_rx_ring; struct pci_dev *pdev = adapter->pdev; int i; if(txdr->desc && txdr->buffer_info) { for(i = 0; i < txdr->count; i++) { if(txdr->buffer_info[i].dma) pci_unmap_single(pdev, txdr->buffer_info[i].dma, txdr->buffer_info[i].length, PCI_DMA_TODEVICE); if(txdr->buffer_info[i].skb) dev_kfree_skb(txdr->buffer_info[i].skb); } } if(rxdr->desc && rxdr->buffer_info) { for(i = 0; i < rxdr->count; i++) { if(rxdr->buffer_info[i].dma) pci_unmap_single(pdev, rxdr->buffer_info[i].dma, rxdr->buffer_info[i].length, PCI_DMA_FROMDEVICE); if(rxdr->buffer_info[i].skb) dev_kfree_skb(rxdr->buffer_info[i].skb); } } if(txdr->desc) pci_free_consistent(pdev, txdr->size, txdr->desc, txdr->dma); if(rxdr->desc) pci_free_consistent(pdev, rxdr->size, rxdr->desc, rxdr->dma);#if 0 if(txdr->buffer_info) kfree(txdr->buffer_info); if(rxdr->buffer_info) kfree(rxdr->buffer_info);#endif return;}static inte1000_setup_desc_rings(struct e1000_adapter *adapter){ struct e1000_desc_ring *txdr = &adapter->diag_tx_ring; struct e1000_desc_ring *rxdr = &adapter->diag_rx_ring; struct pci_dev *pdev = adapter->pdev; uint32_t rctl; int size, i; /* Setup Tx descriptor ring and Tx buffers */ txdr->count = 80; size = txdr->count * sizeof(struct e1000_buffer);#if 0 if(!(txdr->buffer_info = kmalloc(size, GFP_KERNEL))) goto err_nomem;#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -