예제 #1
0
파일: e1000.c 프로젝트: mwilbur/minix
/*===========================================================================*
 *				e1000_init				     *
 *===========================================================================*/
PRIVATE void e1000_init(message *mp)
{
    static int first_time = 1;
    message reply_mess;
    e1000_t *e;

    E1000_DEBUG(3, ("e1000: init()\n"));

    /* Configure PCI devices, if needed. */
    if (first_time)
    {
	first_time = 0;
	e1000_init_pci(); 
    }
    e = &e1000_state;

    /* Initialize hardware, if needed. */
    if (!(e->status & E1000_ENABLED) && !(e1000_init_hw(e)))
    {
        reply_mess.m_type  = DL_CONF_REPLY;
        reply_mess.DL_STAT = ENXIO;
        mess_reply(mp, &reply_mess);
        return;
    }
    /* Reply back to INET. */
    reply_mess.m_type  = DL_CONF_REPLY;
    reply_mess.DL_STAT = OK;
    *(ether_addr_t *) reply_mess.DL_HWADDR = e->address;
    mess_reply(mp, &reply_mess);
}
예제 #2
0
파일: e1000.c 프로젝트: Hooman3/minix
/*
 * Handle an interrupt.
 */
static void
e1000_intr(unsigned int __unused mask)
{
	e1000_t *e;
	u32_t cause;

	E1000_DEBUG(3, ("e1000: interrupt\n"));

	e = &e1000_state;

	/* Reenable interrupts. */
	if (sys_irqenable(&e->irq_hook) != OK)
		panic("failed to re-enable IRQ");

	/* Read the Interrupt Cause Read register. */
	if ((cause = e1000_reg_read(e, E1000_REG_ICR)) != 0) {
		if (cause & E1000_REG_ICR_LSC)
			e1000_link_changed(e);

		if (cause & (E1000_REG_ICR_RXO | E1000_REG_ICR_RXT))
			netdriver_recv();

		if (cause & (E1000_REG_ICR_TXQE | E1000_REG_ICR_TXDW))
			netdriver_send();
	}
}
예제 #3
0
파일: e1000.c 프로젝트: Hooman3/minix
/*
 * Start ICH8 flash cycle.
 */
static int
eeprom_ich_cycle(e1000_t * e, u32_t timeout)
{
	union ich8_hws_flash_ctrl hsflctl;
	union ich8_hws_flash_status hsfsts;
	int ret_val = -1;
	u32_t i = 0;

	E1000_DEBUG(3, ("e1000_flash_cycle_ich8lan"));

	/* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */
	hsflctl.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFCTL);
	hsflctl.hsf_ctrl.flcgo = 1;
	E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFCTL, hsflctl.regval);

	/* Wait till the FDONE bit is set to 1 */
	do {
		hsfsts.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFSTS);
		if (hsfsts.hsf_status.flcdone == 1)
			break;
		tickdelay(1);
	} while (i++ < timeout);

	if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0)
		ret_val = 0;

	return ret_val;
}
예제 #4
0
파일: e1000.c 프로젝트: mwilbur/minix
/*===========================================================================*
 *			   sef_cb_signal_handler			     *
 *===========================================================================*/
PRIVATE void sef_cb_signal_handler(int signo)
{
    E1000_DEBUG(3, ("e1000: got signal\n"));

    /* Only check for termination signal, ignore anything else. */
    if (signo != SIGTERM) return;

    e1000_stop();
}
예제 #5
0
파일: e1000.c 프로젝트: Hooman3/minix
/*
 * Try to receive a packet.
 */
static ssize_t
e1000_recv(struct netdriver_data * data, size_t max)
{
	e1000_t *e;
	e1000_rx_desc_t *desc;
	unsigned int head, tail, cur;
	char *ptr;
	size_t size;

	e = &e1000_state;

	/* If the queue head and tail are equal, the queue is empty. */
	head = e1000_reg_read(e, E1000_REG_RDH);
	tail = e1000_reg_read(e, E1000_REG_RDT);

	E1000_DEBUG(4, ("%s: head=%u, tail=%u\n", e->name, head, tail));

	if (head == tail)
		return SUSPEND;

	/* Has a packet been received? */
	cur = (tail + 1) % e->rx_desc_count;
	desc = &e->rx_desc[cur];

	if (!(desc->status & E1000_RX_STATUS_DONE))
		return SUSPEND;

	/*
	 * HACK: we expect all packets to fit in a single receive buffer.
	 * Eventually, some sort of support to deal with packets spanning
	 * multiple receive descriptors should be added.  For now, we panic,
	 * so that we can continue after the restart; this is already an
	 * improvement over freezing (the old behavior of this driver).
	 */
	size = desc->length;

	if (!(desc->status & E1000_RX_STATUS_EOP))
		panic("received packet too large");

	/* Copy the packet to the caller. */
	ptr = e->rx_buffer + cur * E1000_IOBUF_SIZE;

	if (size > max)
		size = max;

	netdriver_copyout(data, 0, ptr, size);

	/* Reset the descriptor. */
	desc->status = 0;

	/* Increment tail. */
	e1000_reg_write(e, E1000_REG_RDT, cur);

	/* Return the size of the received packet. */
	return size;
}
예제 #6
0
파일: e1000.c 프로젝트: Hooman3/minix
/*
 * Stop the card.
 */
static void
e1000_stop(void)
{
	e1000_t *e;

	e = &e1000_state;

	E1000_DEBUG(3, ("%s: stop()\n", e->name));

	e1000_reset_hw(e);
}
예제 #7
0
파일: e1000.c 프로젝트: Hooman3/minix
/*
 * Initialize and return the card's ethernet address.
 */
static void
e1000_init_addr(e1000_t * e, ether_addr_t * addr)
{
	static char eakey[] = E1000_ENVVAR "#_EA";
	static char eafmt[] = "x:x:x:x:x:x";
	u16_t word;
	int i;
	long v;

	/* Do we have a user defined ethernet address? */
	eakey[sizeof(E1000_ENVVAR)-1] = '0' + e1000_instance;

	for (i = 0; i < 6; i++) {
		if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET)
			break;
		else
			addr->ea_addr[i] = v;
	}

	/* If that fails, read Ethernet Address from EEPROM. */
	if (i != 6) {
		for (i = 0; i < 3; i++) {
			word = e->eeprom_read(e, i);
			addr->ea_addr[i * 2]     = (word & 0x00ff);
			addr->ea_addr[i * 2 + 1] = (word & 0xff00) >> 8;
		}
	}

	/* Set Receive Address. */
	e1000_reg_write(e, E1000_REG_RAL, *(u32_t *)(&addr->ea_addr[0]));
	e1000_reg_write(e, E1000_REG_RAH, *(u16_t *)(&addr->ea_addr[4]));
	e1000_reg_set(e, E1000_REG_RAH, E1000_REG_RAH_AV);
	e1000_reg_set(e, E1000_REG_RCTL, E1000_REG_RCTL_MPE);

	E1000_DEBUG(3, ("%s: Ethernet Address %x:%x:%x:%x:%x:%x\n", e->name,
	    addr->ea_addr[0], addr->ea_addr[1], addr->ea_addr[2],
	    addr->ea_addr[3], addr->ea_addr[4], addr->ea_addr[5]));
}
예제 #8
0
파일: e1000.c 프로젝트: Hooman3/minix
/*
 * Return statistics.
 */
static void
e1000_stat(eth_stat_t * stat)
{
	e1000_t *e = &e1000_state;

	E1000_DEBUG(3, ("e1000: stat()\n"));

	stat->ets_recvErr	= e1000_reg_read(e, E1000_REG_RXERRC);
	stat->ets_sendErr	= 0;
	stat->ets_OVW		= 0;
	stat->ets_CRCerr	= e1000_reg_read(e, E1000_REG_CRCERRS);
	stat->ets_frameAll	= 0;
	stat->ets_missedP	= e1000_reg_read(e, E1000_REG_MPC);
	stat->ets_packetR	= e1000_reg_read(e, E1000_REG_TPR);
	stat->ets_packetT	= e1000_reg_read(e, E1000_REG_TPT);
	stat->ets_collision	= e1000_reg_read(e, E1000_REG_COLC);
	stat->ets_transAb	= 0;
	stat->ets_carrSense	= 0;
	stat->ets_fifoUnder	= 0;
	stat->ets_fifoOver	= 0;
	stat->ets_CDheartbeat	= 0;
	stat->ets_OWC		= 0;
}
예제 #9
0
파일: e1000.c 프로젝트: mwilbur/minix
/*===========================================================================*
 *				e1000_probe				     *
 *===========================================================================*/
PRIVATE int e1000_probe(e1000_t *e, int skip)
{
    int i, r, devind;
    u16_t vid, did;
    u32_t status[2];
    u32_t gfpreg, sector_base_addr;
    char *dname;

    E1000_DEBUG(3, ("%s: probe()\n", e->name));

    /*
     * Attempt to iterate the PCI bus. Start at the beginning.
     */
    if ((r = pci_first_dev(&devind, &vid, &did)) == 0)
    {
	return FALSE;
    }
    /* Loop devices on the PCI bus. */
    for(;;)
    {
	for (i = 0; pcitab_e1000[i] != 0; i++)
	{
	    if (vid != 0x8086)
		continue;
	
	    if (did != pcitab_e1000[i])
		continue;
	    else
		break;
	}
	if (pcitab_e1000[i] != 0)
	{
	    if (!skip)
		break;
	    skip--;
	}

	if (!(r = pci_next_dev(&devind, &vid, &did)))
	{
	    return FALSE;
	}
    }
    /*
     * Successfully detected an Intel Pro/1000 on the PCI bus.
     */
    e->status |= E1000_DETECTED;
    e->eeprom_read = eeprom_eerd;
    
    /*
     * Set card specific properties.
     */
    switch (did)
    {
        case E1000_DEV_ID_ICH10_R_BM_LF:
            e->eeprom_read = eeprom_ich;
            break;

    	case E1000_DEV_ID_82574L:
	case E1000_DEV_ID_82541GI_LF:
	    e->eeprom_done_bit = (1 << 1);
	    e->eeprom_addr_off =  2;
	    break;

	default:
	    e->eeprom_done_bit = (1 << 4);
	    e->eeprom_addr_off =  8;
	    break;
    }

    /* Inform the user about the new card. */
    if (!(dname = pci_dev_name(vid, did)))
    {
        dname = "Intel Pro/1000 Gigabit Ethernet Card";
    }
    E1000_DEBUG(1, ("%s: %s (%04x/%04x/%02x) at %s\n",
		     e->name, dname, vid, did, e->revision, 
		     pci_slot_name(devind)));

    /* Reserve PCI resources found. */
    if ((r = pci_reserve_ok(devind)) != OK)
    {
        panic("failed to reserve PCI device: %d", r);
    }
    /* Read PCI configuration. */
    e->irq   = pci_attr_r8(devind, PCI_ILR);
    e->regs  = vm_map_phys(SELF, (void *) pci_attr_r32(devind, PCI_BAR), 
			   0x20000);
			   
    /* Verify mapped registers. */
    if (e->regs == (u8_t *) -1) {
		panic("failed to map hardware registers from PCI");
    }
    /* Optionally map flash memory. */
    if (did != E1000_DEV_ID_82540EM &&
	did != E1000_DEV_ID_82540EP &&
	pci_attr_r32(devind, PCI_BAR_2))
    {
       if((e->flash = vm_map_phys(SELF,
         (void *) pci_attr_r32(devind, PCI_BAR_2), 0x10000)) == MAP_FAILED) {
               if((e->flash = vm_map_phys(SELF,
                       (void *) pci_attr_r32(devind, PCI_BAR_2), 0x1000))
                               == MAP_FAILED) {
                               panic("e1000: couldn't map in flash.");
               }
       }

	gfpreg = E1000_READ_FLASH_REG(e, ICH_FLASH_GFPREG);
        /*
         * sector_base_addr is a "sector"-aligned address (4096 bytes)
         */
        sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK;

        /* flash_base_addr is byte-aligned */
        e->flash_base_addr = sector_base_addr << FLASH_SECTOR_ADDR_SHIFT;
    }
    /*
     * Output debug information.
     */
    status[0] = e1000_reg_read(e, E1000_REG_STATUS);    
    E1000_DEBUG(3, ("%s: MEM at %p, IRQ %d\n",
		    e->name, e->regs, e->irq));
    E1000_DEBUG(3, ("%s: link %s, %s duplex\n",
		    e->name, status[0] & 3 ? "up"   : "down",
			     status[0] & 1 ? "full" : "half"));
    return TRUE;
}
예제 #10
0
파일: e1000.c 프로젝트: Hooman3/minix
/*
 * Read from ICH8 flash.
 */
static u16_t
eeprom_ich(e1000_t * e, int reg)
{
	union ich8_hws_flash_status hsfsts;
	union ich8_hws_flash_ctrl hsflctl;
	u32_t flash_linear_addr;
	u32_t flash_data = 0;
	int ret_val = -1;
	u8_t count = 0;
	u16_t data = 0;

	E1000_DEBUG(3, ("e1000_read_flash_data_ich8lan"));

	if (reg > ICH_FLASH_LINEAR_ADDR_MASK)
		return data;

	reg *= sizeof(u16_t);
	flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & reg) +
	    e->flash_base_addr;

	do {
		tickdelay(1);

		/* Steps */
		ret_val = eeprom_ich_init(e);
		if (ret_val != 0)
			break;

		hsflctl.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFCTL);
		/* 0b/1b corresponds to 1 or 2 byte size, respectively. */
		hsflctl.hsf_ctrl.fldbcount = 1;
		hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ;
		E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFCTL, hsflctl.regval);
		E1000_WRITE_FLASH_REG(e, ICH_FLASH_FADDR, flash_linear_addr);

		ret_val = eeprom_ich_cycle(e, ICH_FLASH_READ_COMMAND_TIMEOUT);

		/*
		 * Check if FCERR is set to 1, if set to 1, clear it and try
		 * the whole sequence a few more times, else read in (shift in)
		 * the Flash Data0, the order is least significant byte first
		 * msb to lsb.
		 */
		if (ret_val == 0) {
			flash_data = E1000_READ_FLASH_REG(e, ICH_FLASH_FDATA0);
			data = (u16_t)(flash_data & 0x0000FFFF);
			break;
		} else {
			/*
			 * If we've gotten here, then things are probably
			 * completely hosed, but if the error condition is
			 * detected, it won't hurt to give it another try...
			 * ICH_FLASH_CYCLE_REPEAT_COUNT times.
			 */
			hsfsts.regval = E1000_READ_FLASH_REG16(e,
			    ICH_FLASH_HSFSTS);

			if (hsfsts.hsf_status.flcerr == 1) {
				/* Repeat for some time before giving up. */
				continue;
			} else if (hsfsts.hsf_status.flcdone == 0) {
				E1000_DEBUG(3, ("Timeout error - flash cycle "
				    "did not complete."));
				break;
			}
		}
	} while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);

	return data;
}
예제 #11
0
파일: e1000.c 프로젝트: Hooman3/minix
/*
 * Initialize ICH8 flash.
 */
static int
eeprom_ich_init(e1000_t * e)
{
	union ich8_hws_flash_status hsfsts;
	int ret_val = -1;
	int i = 0;

	hsfsts.regval = E1000_READ_FLASH_REG16(e, ICH_FLASH_HSFSTS);

	/* Check if the flash descriptor is valid */
	if (hsfsts.hsf_status.fldesvalid == 0) {
		E1000_DEBUG(3, ("Flash descriptor invalid. "
		    "SW Sequencing must be used."));
		return ret_val;
	}

	/* Clear FCERR and DAEL in hw status by writing 1 */
	hsfsts.hsf_status.flcerr = 1;
	hsfsts.hsf_status.dael = 1;

	E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFSTS, hsfsts.regval);

	/*
	 * Either we should have a hardware SPI cycle in progress bit to check
	 * against, in order to start a new cycle or FDONE bit should be
	 * changed in the hardware so that it is 1 after hardware reset, which
	 * can then be used as an indication whether a cycle is in progress or
	 * has been completed.
	 */
	if (hsfsts.hsf_status.flcinprog == 0) {
		/*
		 * There is no cycle running at present, so we can start a
		 * cycle.  Begin by setting Flash Cycle Done.
		 */
		hsfsts.hsf_status.flcdone = 1;
		E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFSTS, hsfsts.regval);
		ret_val = 0;
	} else {
		/*
		 * Otherwise poll for sometime so the current cycle has a
		 * chance to end before giving up.
		 */
		for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) {
			hsfsts.regval = E1000_READ_FLASH_REG16(e,
			    ICH_FLASH_HSFSTS);

			if (hsfsts.hsf_status.flcinprog == 0) {
				ret_val = 0;
				break;
			}
			tickdelay(1);
		}
		if (ret_val == 0) {
			/*
			 * Successful in waiting for previous cycle to timeout,
			 * now set the Flash Cycle Done.
			 */
			hsfsts.hsf_status.flcdone = 1;
			E1000_WRITE_FLASH_REG16(e, ICH_FLASH_HSFSTS,
			    hsfsts.regval);
		} else {
			E1000_DEBUG(3,
			    ("Flash controller busy, cannot get access"));
		}
	}

	return ret_val;
}
예제 #12
0
파일: e1000.c 프로젝트: Hooman3/minix
/*
 * Link status has changed.  Nothing to do for now.
 */
static void
e1000_link_changed(e1000_t * e)
{

	E1000_DEBUG(4, ("%s: link_changed()\n", e->name));
}
예제 #13
0
파일: e1000.c 프로젝트: Hooman3/minix
/*
 * Find a matching device.  Return TRUE on success.
 */
static int
e1000_probe(e1000_t * e, int skip)
{
	int r, devind, ioflag;
	u16_t vid, did, cr;
	u32_t status;
	u32_t base, size;
	char *dname;

	E1000_DEBUG(3, ("%s: probe()\n", e->name));

	/* Initialize communication to the PCI driver. */
	pci_init();

	/* Attempt to iterate the PCI bus. Start at the beginning. */
	if ((r = pci_first_dev(&devind, &vid, &did)) == 0)
		return FALSE;

	/* Loop devices on the PCI bus. */
	while (skip--) {
		E1000_DEBUG(3, ("%s: probe() devind %d vid 0x%x did 0x%x\n",
		    e->name, devind, vid, did));

		if (!(r = pci_next_dev(&devind, &vid, &did)))
			return FALSE;
	}

	/* We found a matching card.  Set card-specific properties. */
	e->eeprom_read = eeprom_eerd;

	switch (did) {
	case E1000_DEV_ID_ICH10_D_BM_LM:
	case E1000_DEV_ID_ICH10_R_BM_LF:
		e->eeprom_read = eeprom_ich;
		break;

	case E1000_DEV_ID_82540EM:
	case E1000_DEV_ID_82545EM:
	case E1000_DEV_ID_82540EP_LP:
		e->eeprom_done_bit = (1 << 4);
		e->eeprom_addr_off = 8;
		break;

	default:
		e->eeprom_done_bit = (1 << 1);
		e->eeprom_addr_off = 2;
		break;
	}

	/* Inform the user about the new card. */
	if (!(dname = pci_dev_name(vid, did)))
		dname = "Intel Pro/1000 Gigabit Ethernet Card";
	E1000_DEBUG(1, ("%s: %s (%04x/%04x) at %s\n",
	    e->name, dname, vid, did, pci_slot_name(devind)));

	/* Reserve PCI resources found. */
	pci_reserve(devind);

	/* Read PCI configuration. */
	e->irq = pci_attr_r8(devind, PCI_ILR);

	if ((r = pci_get_bar(devind, PCI_BAR, &base, &size, &ioflag)) != OK)
		panic("failed to get PCI BAR: %d", r);
	if (ioflag)
		panic("PCI BAR is not for memory");

	if ((e->regs = vm_map_phys(SELF, (void *)base, size)) == MAP_FAILED)
		panic("failed to map hardware registers from PCI");

	/* Enable DMA bus mastering if necessary. */
	cr = pci_attr_r16(devind, PCI_CR);
	if (!(cr & PCI_CR_MAST_EN))
		pci_attr_w16(devind, PCI_CR, cr | PCI_CR_MAST_EN);

	/* Optionally map flash memory. */
	e1000_map_flash(e, devind, did);

	/* Output debug information. */
	status = e1000_reg_read(e, E1000_REG_STATUS);
	E1000_DEBUG(3, ("%s: MEM at %p, IRQ %d\n", e->name, e->regs, e->irq));
	E1000_DEBUG(3, ("%s: link %s, %s duplex\n", e->name,
	    status & 3 ? "up"   : "down", status & 1 ? "full" : "half"));

	return TRUE;
}