Skip to content
Snippets Groups Projects
e1000.c 152 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	/*DEBUGOUT("recv: packet len=%d \n", rd->length); */
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	NetReceive((uchar *)packet, le32_to_cpu(rd->length));
    
    	fill_rx(hw);
    	return 1;
    }
    
    /**************************************************************************
    TRANSMIT - Transmit a frame
    ***************************************************************************/
    static int
    e1000_transmit(struct eth_device *nic, volatile void *packet, int length)
    {
    	struct e1000_hw *hw = nic->priv;
    	struct e1000_tx_desc *txp;
    	int i = 0;
    
    	txp = tx_base + tx_tail;
    	tx_tail = (tx_tail + 1) % 8;
    
    	txp->buffer_addr = cpu_to_le64(virt_to_bus(packet));
    
    	txp->lower.data = cpu_to_le32(hw->txd_cmd | length);
    
    	txp->upper.data = 0;
    	E1000_WRITE_REG(hw, TDT, tx_tail);
    
    
    	E1000_WRITE_FLUSH(hw);
    
    	while (!(le32_to_cpu(txp->upper.data) & E1000_TXD_STAT_DD)) {
    		if (i++ > TOUT_LOOP) {
    			DEBUGOUT("e1000: tx timeout\n");
    			return 0;
    		}
    		udelay(10);	/* give the nic a chance to write to the register */
    	}
    	return 1;
    }
    
    /*reset function*/
    static inline int
    e1000_reset(struct eth_device *nic)
    {
    	struct e1000_hw *hw = nic->priv;
    
    	e1000_reset_hw(hw);
    	if (hw->mac_type >= e1000_82544) {
    		E1000_WRITE_REG(hw, WUC, 0);
    	}
    	return e1000_init_hw(nic);
    }
    
    /**************************************************************************
    DISABLE - Turn off ethernet interface
    ***************************************************************************/
    static void
    e1000_disable(struct eth_device *nic)
    {
    	struct e1000_hw *hw = nic->priv;
    
    	/* Turn off the ethernet interface */
    	E1000_WRITE_REG(hw, RCTL, 0);
    	E1000_WRITE_REG(hw, TCTL, 0);
    
    	/* Clear the transmit ring */
    	E1000_WRITE_REG(hw, TDH, 0);
    	E1000_WRITE_REG(hw, TDT, 0);
    
    	/* Clear the receive ring */
    	E1000_WRITE_REG(hw, RDH, 0);
    	E1000_WRITE_REG(hw, RDT, 0);
    
    	/* put the card in its initial state */
    #if 0
    	E1000_WRITE_REG(hw, CTRL, E1000_CTRL_RST);
    #endif
    	mdelay(10);
    
    }
    
    /**************************************************************************
    INIT - set up ethernet interface(s)
    ***************************************************************************/
    static int
    e1000_init(struct eth_device *nic, bd_t * bis)
    {
    	struct e1000_hw *hw = nic->priv;
    	int ret_val = 0;
    
    	ret_val = e1000_reset(nic);
    	if (ret_val < 0) {
    		if ((ret_val == -E1000_ERR_NOLINK) ||
    		    (ret_val == -E1000_ERR_TIMEOUT)) {
    			E1000_ERR("Valid Link not detected\n");
    		} else {
    			E1000_ERR("Hardware Initialization Failed\n");
    		}
    		return 0;
    	}
    	e1000_configure_tx(hw);
    	e1000_setup_rctl(hw);
    	e1000_configure_rx(hw);
    	return 1;
    }
    
    
    /******************************************************************************
     * Gets the current PCI bus type of hardware
     *
     * hw - Struct containing variables accessed by shared code
     *****************************************************************************/
    void e1000_get_bus_type(struct e1000_hw *hw)
    {
    	uint32_t status;
    
    	switch (hw->mac_type) {
    	case e1000_82542_rev2_0:
    	case e1000_82542_rev2_1:
    		hw->bus_type = e1000_bus_type_pci;
    		break;
    	case e1000_82571:
    	case e1000_82572:
    	case e1000_82573:
    	case e1000_80003es2lan:
    		hw->bus_type = e1000_bus_type_pci_express;
    		break;
    	case e1000_ich8lan:
    		hw->bus_type = e1000_bus_type_pci_express;
    		break;
    	default:
    		status = E1000_READ_REG(hw, STATUS);
    		hw->bus_type = (status & E1000_STATUS_PCIX_MODE) ?
    				e1000_bus_type_pcix : e1000_bus_type_pci;
    		break;
    	}
    }
    
    
    /**************************************************************************
    PROBE - Look for an adapter, this routine's visible to the outside
    You should omit the last argument struct pci_device * for a non-PCI NIC
    ***************************************************************************/
    int
    e1000_initialize(bd_t * bis)
    {
    	pci_dev_t devno;
    	int card_number = 0;
    	struct eth_device *nic = NULL;
    	struct e1000_hw *hw = NULL;
    	u32 iobase;
    	int idx = 0;
    	u32 PciCommandWord;
    
    	while (1) {		/* Find PCI device(s) */
    		if ((devno = pci_find_devices(supported, idx++)) < 0) {
    			break;
    		}
    
    		pci_read_config_dword(devno, PCI_BASE_ADDRESS_0, &iobase);
    		iobase &= ~0xf;	/* Mask the bits that say "this is an io addr" */
    		DEBUGOUT("e1000#%d: iobase 0x%08x\n", card_number, iobase);
    
    		pci_write_config_dword(devno, PCI_COMMAND,
    				       PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
    		/* Check if I/O accesses and Bus Mastering are enabled. */
    		pci_read_config_dword(devno, PCI_COMMAND, &PciCommandWord);
    		if (!(PciCommandWord & PCI_COMMAND_MEMORY)) {
    			printf("Error: Can not enable MEM access.\n");
    			continue;
    		} else if (!(PciCommandWord & PCI_COMMAND_MASTER)) {
    			printf("Error: Can not enable Bus Mastering.\n");
    			continue;
    		}
    
    		nic = (struct eth_device *) malloc(sizeof (*nic));
    		hw = (struct e1000_hw *) malloc(sizeof (*hw));
    		hw->pdev = devno;
    		nic->priv = hw;
    		nic->iobase = bus_to_phys(devno, iobase);
    
    		sprintf(nic->name, "e1000#%d", card_number);
    
    		/* Are these variables needed? */
    		hw->fc = e1000_fc_default;
    		hw->original_fc = e1000_fc_default;
    		hw->autoneg_failed = 0;
    
    		hw->autoneg = 1;
    
    		hw->get_link_status = TRUE;
    		hw->hw_addr = (typeof(hw->hw_addr)) iobase;
    		hw->mac_type = e1000_undefined;
    
    		/* MAC and Phy settings */
    		if (e1000_sw_init(nic, card_number) < 0) {
    			free(hw);
    			free(nic);
    			return 0;
    		}
    
    		if (e1000_check_phy_reset_block(hw))
    			printf("phy reset block error \n");
    		e1000_reset_hw(hw);
    
    Andre Schwarz's avatar
    Andre Schwarz committed
    #if !(defined(CONFIG_AP1000) || defined(CONFIG_MVBC_1G))
    
    		if (e1000_init_eeprom_params(hw)) {
    			printf("The EEPROM Checksum Is Not Valid\n");
    			free(hw);
    			free(nic);
    			return 0;
    		}
    
    		if (e1000_validate_eeprom_checksum(nic) < 0) {
    			printf("The EEPROM Checksum Is Not Valid\n");
    			free(hw);
    			free(nic);
    			return 0;
    		}
    
    		e1000_read_mac_addr(nic);
    
    
    		/* get the bus type information */
    		e1000_get_bus_type(hw);
    
    
    		printf("e1000: %02x:%02x:%02x:%02x:%02x:%02x\n",
    		       nic->enetaddr[0], nic->enetaddr[1], nic->enetaddr[2],
    		       nic->enetaddr[3], nic->enetaddr[4], nic->enetaddr[5]);
    
    		nic->init = e1000_init;
    		nic->recv = e1000_poll;
    		nic->send = e1000_transmit;
    		nic->halt = e1000_disable;
    
    		eth_register(nic);
    
    		card_number++;
    	}