minix/drivers/e1000/e1000.c
2010-04-15 18:49:36 +00:00

1259 lines
36 KiB
C

/**
* @file e1000.c
*
* @brief This file contains a device driver for Intel Pro/1000
* Gigabit Ethernet Controllers.
*/
#include <minix/drivers.h>
#include <minix/netdriver.h>
#include <stdlib.h>
#include <net/gen/ether.h>
#include <net/gen/eth_io.h>
#include <machine/pci.h>
#include <minix/ds.h>
#include <minix/vm.h>
#include <timers.h>
#include "assert.h"
#include "e1000.h"
#include "e1000_hw.h"
#include "e1000_reg.h"
#include "e1000_pci.h"
PRIVATE u16_t pcitab_e1000[] =
{
E1000_DEV_ID_82540EM,
E1000_DEV_ID_82541GI_LF,
E1000_DEV_ID_ICH10_R_BM_LF,
0,
};
PRIVATE const char *progname;
PRIVATE e1000_t e1000_table[E1000_PORT_NR];
_PROTOTYPE( PRIVATE void e1000_init, (message *mp) );
_PROTOTYPE( PRIVATE void e1000_init_pci, (void) );
_PROTOTYPE( PRIVATE int e1000_probe, (e1000_t *e) );
_PROTOTYPE( PRIVATE int e1000_init_hw, (e1000_t *e) );
_PROTOTYPE( PRIVATE void e1000_init_addr, (e1000_t *e) );
_PROTOTYPE( PRIVATE void e1000_init_buf, (e1000_t *e) );
_PROTOTYPE( PRIVATE void e1000_reset_hw, (e1000_t *e) );
_PROTOTYPE( PRIVATE void e1000_writev_s, (message *mp, int from_int) );
_PROTOTYPE( PRIVATE void e1000_readv_s, (message *mp, int from_int) );
_PROTOTYPE( PRIVATE void e1000_getstat_s, (message *mp) );
_PROTOTYPE( PRIVATE void e1000_getname, (message *mp) );
_PROTOTYPE( PRIVATE void e1000_interrupt, (message *mp) );
_PROTOTYPE( PRIVATE int e1000_link_changed, (e1000_t *e) );
_PROTOTYPE( PRIVATE void e1000_stop, (void) );
_PROTOTYPE( PRIVATE e1000_t * e1000_port, (int port) );
_PROTOTYPE( PRIVATE uint32_t e1000_reg_read, (e1000_t *e, uint32_t reg) );
_PROTOTYPE( PRIVATE void e1000_reg_write, (e1000_t *e, uint32_t reg,
uint32_t value) );
_PROTOTYPE( PRIVATE void e1000_reg_set, (e1000_t *e, uint32_t reg,
uint32_t value) );
_PROTOTYPE( PRIVATE void e1000_reg_unset, (e1000_t *e, uint32_t reg,
uint32_t value) );
_PROTOTYPE( PRIVATE u16_t eeprom_eerd, (void *e, int reg) );
_PROTOTYPE( PRIVATE u16_t eeprom_ich, (void *e, int reg) );
_PROTOTYPE( PRIVATE int eeprom_ich_init, (e1000_t *e) );
_PROTOTYPE( PRIVATE int eeprom_ich_cycle, (const e1000_t *e, u32_t timeout) );
_PROTOTYPE( PRIVATE void reply, (e1000_t *e, int err, int may_block) );
_PROTOTYPE( PRIVATE void mess_reply, (message *req, message *reply) );
/* SEF functions and variables. */
FORWARD _PROTOTYPE( void sef_local_startup, (void) );
FORWARD _PROTOTYPE( int sef_cb_init_fresh, (int type, sef_init_info_t *info) );
FORWARD _PROTOTYPE( void sef_cb_signal_handler, (int signo) );
EXTERN int env_argc;
EXTERN char **env_argv;
/*===========================================================================*
* main *
*===========================================================================*/
int main(int argc, char *argv[])
{
message m;
int ipc_status;
int r;
/* SEF local startup. */
env_setargs(argc, argv);
sef_local_startup();
/*
* Enter the main driver loop.
*/
while (TRUE)
{
if ((r= netdriver_receive(ANY, &m, &ipc_status)) != OK)
{
panic("netdriver_receive failed: %d", r);
}
if (is_ipc_notify(ipc_status))
{
switch (_ENDPOINT_P(m.m_source))
{
case HARDWARE:
e1000_interrupt(&m);
break;
case CLOCK:
break;
}
continue;
}
switch (m.m_type)
{
case DL_WRITEV_S: e1000_writev_s(&m, FALSE); break;
case DL_READV_S: e1000_readv_s(&m, FALSE); break;
case DL_CONF: e1000_init(&m); break;
case DL_STOP: e1000_stop(); break;
case DL_GETSTAT_S: e1000_getstat_s(&m); break;
case DL_GETNAME: e1000_getname(&m); break;
default:
panic("illegal message: %d", m.m_type);
}
}
}
/*===========================================================================*
* sef_local_startup *
*===========================================================================*/
PRIVATE void sef_local_startup()
{
/* Register init callbacks. */
sef_setcb_init_fresh(sef_cb_init_fresh);
sef_setcb_init_lu(sef_cb_init_fresh);
sef_setcb_init_restart(sef_cb_init_fresh);
/* Register live update callbacks. */
sef_setcb_lu_prepare(sef_cb_lu_prepare_always_ready);
sef_setcb_lu_state_isvalid(sef_cb_lu_state_isvalid_workfree);
/* Register signal callbacks. */
sef_setcb_signal_handler(sef_cb_signal_handler);
/* Let SEF perform startup. */
sef_startup();
}
/*===========================================================================*
* sef_cb_init_fresh *
*===========================================================================*/
PRIVATE int sef_cb_init_fresh(int UNUSED(type), sef_init_info_t *UNUSED(info))
{
/* Initialize the e1000 driver. */
int r;
/* Verify command-line arguments. */
if (env_argc < 1)
{
panic("no program name given in argc/argv");
}
else
(progname = strrchr(env_argv[0],'/')) ? progname++
: (progname = env_argv[0]);
/* Clear state. */
memset(e1000_table, 0, sizeof(e1000_table));
/* Perform calibration. */
if((r = tsc_calibrate()) != OK)
{
panic("tsc_calibrate failed: %d", r);
}
/* Announce we are up! */
netdriver_announce();
return(OK);
}
/*===========================================================================*
* 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();
}
/*===========================================================================*
* 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();
}
/* Retrieve e1000 pointer. */
e = e1000_port(mp->DL_PORT);
e->client = mp->DL_PROC;
/* Initialize hardware, if needed. */
if (!(e->status & E1000_ENABLED) && !(e1000_init_hw(e)))
{
reply_mess.m_type = DL_CONF_REPLY;
reply_mess.m3_i1 = ENXIO;
mess_reply(mp, &reply_mess);
return;
}
/* Reply back to INET. */
reply_mess.m_type = DL_CONF_REPLY;
reply_mess.m3_i1 = mp->DL_PORT;
reply_mess.m3_i2 = E1000_PORT_NR;
*(ether_addr_t *) reply_mess.m3_ca1 = e->address;
mess_reply(mp, &reply_mess);
}
/*===========================================================================*
* e1000_int_pci *
*===========================================================================*/
PRIVATE void e1000_init_pci()
{
e1000_t *e;
int i;
/* Initialize the PCI bus. */
pci_init();
/* Try to detect e1000's. */
for (i = 0, e = &e1000_table[i]; i < E1000_PORT_NR; i++, e++)
{
strcpy(e->name, "e1000#0");
e->name[6] += i;
e1000_probe(e);
}
}
/*===========================================================================*
* e1000_probe *
*===========================================================================*/
PRIVATE int e1000_probe(e1000_t *e)
{
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)
break;
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_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 (pci_attr_r32(devind, PCI_BAR_3))
{
e->flash = vm_map_phys(SELF, (void *) pci_attr_r32(devind, PCI_BAR_2),
0x10000);
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 0x%lx, 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;
}
/*===========================================================================*
* e1000_init_hw *
*===========================================================================*/
PRIVATE int e1000_init_hw(e)
e1000_t *e;
{
int r, i;
e->status |= E1000_ENABLED;
e->irq_hook = e->irq;
/*
* Set the interrupt handler and policy. Do not automatically
* re-enable interrupts. Return the IRQ line number on interrupts.
*/
if ((r = sys_irqsetpolicy(e->irq, 0, &e->irq_hook)) != OK)
{
panic("sys_irqsetpolicy failed: %d", r);
}
if ((r = sys_irqenable(&e->irq_hook)) != OK)
{
panic("sys_irqenable failed: %d", r);
}
/* Reset hardware. */
e1000_reset_hw(e);
/*
* Initialize appropriately, according to section 14.3 General Configuration
* of Intel's Gigabit Ethernet Controllers Software Developer's Manual.
*/
e1000_reg_set(e, E1000_REG_CTRL, E1000_REG_CTRL_ASDE | E1000_REG_CTRL_SLU);
e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_LRST);
e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_PHY_RST);
e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_ILOS);
e1000_reg_write(e, E1000_REG_FCAL, 0);
e1000_reg_write(e, E1000_REG_FCAH, 0);
e1000_reg_write(e, E1000_REG_FCT, 0);
e1000_reg_write(e, E1000_REG_FCTTV, 0);
e1000_reg_unset(e, E1000_REG_CTRL, E1000_REG_CTRL_VME);
/* Clear Multicast Table Array (MTA). */
for (i = 0; i < 128; i++)
{
e1000_reg_write(e, E1000_REG_MTA + i, 0);
}
/* Initialize statistics registers. */
for (i = 0; i < 64; i++)
{
e1000_reg_write(e, E1000_REG_CRCERRS + (i * 4), 0);
}
/*
* Aquire MAC address and setup RX/TX buffers.
*/
e1000_init_addr(e);
e1000_init_buf(e);
/* Enable interrupts. */
e1000_reg_set(e, E1000_REG_IMS, E1000_REG_IMS_LSC |
E1000_REG_IMS_RXO |
E1000_REG_IMS_RXT |
E1000_REG_IMS_TXQE |
E1000_REG_IMS_TXDW);
return TRUE;
}
/*===========================================================================*
* e1000_init_addr *
*===========================================================================*/
PRIVATE void e1000_init_addr(e)
e1000_t *e;
{
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' + (e-e1000_table);
for (i= 0; i < 6; i++)
{
if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET)
break;
else
e->address.ea_addr[i]= v;
}
/*
* If that fails, read Ethernet Address from EEPROM.
*/
if ((i != 0 && i != 6) || i == 0)
{
for (i = 0; i < 3; i++)
{
word = e->eeprom_read(e, i);
e->address.ea_addr[(i * 2)] = (word & 0xff);
e->address.ea_addr[(i * 2) + 1] = (word & 0xff00) >> 8;
}
}
/*
* Set Receive Address.
*/
e1000_reg_write(e, E1000_REG_RAL, *(u32_t *)(&e->address.ea_addr[0]));
e1000_reg_write(e, E1000_REG_RAH, *(u16_t *)(&e->address.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,
e->address.ea_addr[0], e->address.ea_addr[1],
e->address.ea_addr[2], e->address.ea_addr[3],
e->address.ea_addr[4], e->address.ea_addr[5]));
}
/*===========================================================================*
* e1000_init_buf *
*===========================================================================*/
PRIVATE void e1000_init_buf(e)
e1000_t *e;
{
phys_bytes rx_desc_p, rx_buff_p;
phys_bytes tx_desc_p, tx_buff_p;
int i;
/* Number of descriptors. */
e->rx_desc_count = E1000_RXDESC_NR;
e->tx_desc_count = E1000_TXDESC_NR;
/*
* First, allocate the receive descriptors.
*/
if (!e->rx_desc)
{
if ((e->rx_desc = alloc_contig(sizeof(e1000_rx_desc_t) *
e->rx_desc_count, AC_ALIGN4K,
&rx_desc_p)) == NULL) {
panic("failed to allocate RX descriptors");
}
memset(e->rx_desc, 0, sizeof(e1000_rx_desc_t) * e->rx_desc_count);
/*
* Allocate 2048-byte buffers.
*/
e->rx_buffer_size = E1000_RXDESC_NR * E1000_IOBUF_SIZE;
/* Attempt to allocate. */
if ((e->rx_buffer = alloc_contig(e->rx_buffer_size,
AC_ALIGN4K, &rx_buff_p)) == NULL)
{
panic("failed to allocate RX buffers");
}
/* Setup receive descriptors. */
for (i = 0; i < E1000_RXDESC_NR; i++)
{
e->rx_desc[i].buffer = rx_buff_p + (i * E1000_IOBUF_SIZE);
}
}
/*
* Then, allocate transmit descriptors.
*/
if (!e->tx_desc)
{
if ((e->tx_desc = alloc_contig(sizeof(e1000_tx_desc_t) *
e->tx_desc_count, AC_ALIGN4K,
&tx_desc_p)) == NULL) {
panic("failed to allocate TX descriptors");
}
memset(e->tx_desc, 0, sizeof(e1000_tx_desc_t) * e->tx_desc_count);
/*
* Allocate 2048-byte buffers.
*/
e->tx_buffer_size = E1000_TXDESC_NR * E1000_IOBUF_SIZE;
/* Attempt to allocate. */
if ((e->tx_buffer = alloc_contig(e->tx_buffer_size,
AC_ALIGN4K, &tx_buff_p)) == NULL)
{
panic("failed to allocate TX buffers");
}
/* Setup transmit descriptors. */
for (i = 0; i < E1000_RXDESC_NR; i++)
{
e->tx_desc[i].buffer = tx_buff_p + (i * E1000_IOBUF_SIZE);
}
}
/*
* Setup the receive ring registers.
*/
e1000_reg_write(e, E1000_REG_RDBAL, rx_desc_p);
e1000_reg_write(e, E1000_REG_RDBAH, 0);
e1000_reg_write(e, E1000_REG_RDLEN, e->rx_desc_count *
sizeof(e1000_rx_desc_t));
e1000_reg_write(e, E1000_REG_RDH, 0);
e1000_reg_write(e, E1000_REG_RDT, e->rx_desc_count - 1);
e1000_reg_unset(e, E1000_REG_RCTL, E1000_REG_RCTL_BSIZE);
e1000_reg_set(e, E1000_REG_RCTL, E1000_REG_RCTL_EN);
/*
* Setup the transmit ring registers.
*/
e1000_reg_write(e, E1000_REG_TDBAL, tx_desc_p);
e1000_reg_write(e, E1000_REG_TDBAH, 0);
e1000_reg_write(e, E1000_REG_TDLEN, e->tx_desc_count *
sizeof(e1000_tx_desc_t));
e1000_reg_write(e, E1000_REG_TDH, 0);
e1000_reg_write(e, E1000_REG_TDT, 0);
e1000_reg_set( e, E1000_REG_TCTL, E1000_REG_TCTL_EN | E1000_REG_TCTL_PSP);
}
/*===========================================================================*
* e1000_reset_hw *
*===========================================================================*/
PRIVATE void e1000_reset_hw(e)
e1000_t *e;
{
/* Assert a Device Reset signal. */
e1000_reg_set(e, E1000_REG_CTRL, E1000_REG_CTRL_RST);
/* Wait one microsecond. */
tickdelay(1);
}
/*===========================================================================*
* e1000_writev_s *
*===========================================================================*/
PRIVATE void e1000_writev_s(mp, from_int)
message *mp;
int from_int;
{
e1000_t *e = e1000_port(mp->DL_PORT);
e1000_tx_desc_t *desc;
iovec_s_t iovec[E1000_IOVEC_NR];
int r, head, tail, i, bytes = 0, size;
E1000_DEBUG(3, ("e1000: writev_s(%x,%d)\n", mp, from_int));
/* Are we called from the interrupt handler? */
if (!from_int)
{
/* We cannot write twice simultaneously.
assert(!(e->status & E1000_WRITING)); */
/* Copy write message. */
e->tx_message = *mp;
e->status |= E1000_WRITING;
/* Must be a sane vector count. */
assert(e->tx_message.DL_COUNT > 0);
assert(e->tx_message.DL_COUNT < E1000_IOVEC_NR);
/*
* Copy the I/O vector table.
*/
if ((r = sys_safecopyfrom(e->client, e->tx_message.DL_GRANT, 0,
(vir_bytes) iovec, e->tx_message.DL_COUNT *
sizeof(iovec_s_t), D)) != OK)
{
panic("sys_safecopyfrom() failed: %d", r);
}
/* Find the head, tail and current descriptors. */
head = e1000_reg_read(e, E1000_REG_TDH);
tail = e1000_reg_read(e, E1000_REG_TDT);
desc = &e->tx_desc[tail];
E1000_DEBUG(4, ("%s: head=%d, tail=%d\n",
e->name, head, tail));
/* Loop vector elements. */
for (i = 0; i < e->tx_message.DL_COUNT; i++)
{
size = iovec[i].iov_size < (E1000_IOBUF_SIZE - bytes) ?
iovec[i].iov_size : (E1000_IOBUF_SIZE - bytes);
E1000_DEBUG(4, ("iovec[%d] = %d\n", i, size));
/* Copy bytes to TX queue buffers. */
if ((r = sys_safecopyfrom(e->client, iovec[i].iov_grant, 0,
(vir_bytes) e->tx_buffer +
(tail * E1000_IOBUF_SIZE),
size, D)) != OK)
{
panic("sys_safecopyfrom() failed: %d", r);
}
/* Mark this descriptor ready. */
desc->status = 0;
desc->command = 0;
desc->length = size;
/* Marks End-of-Packet. */
if (i == e->tx_message.DL_COUNT - 1)
{
desc->command = E1000_TX_CMD_EOP |
E1000_TX_CMD_FCS |
E1000_TX_CMD_RS;
}
/* Move to next descriptor. */
tail = (tail + 1) % e->tx_desc_count;
bytes += size;
desc = &e->tx_desc[tail];
}
/* Increment tail. Start transmission. */
e1000_reg_write(e, E1000_REG_TDT, tail);
E1000_DEBUG(2, ("e1000: wrote %d byte packet\n", bytes));
}
else
{
e->status |= E1000_TRANSMIT;
}
reply(e, OK, FALSE);
}
/*===========================================================================*
* e1000_readv_s *
*===========================================================================*/
PRIVATE void e1000_readv_s(mp, from_int)
message *mp;
int from_int;
{
e1000_t *e = e1000_port(mp->DL_PORT);
e1000_rx_desc_t *desc;
iovec_s_t iovec[E1000_IOVEC_NR];
int i, r, head, tail, cur, bytes = 0, size;
E1000_DEBUG(3, ("e1000: readv_s(%x,%d)\n", mp, from_int));
/* Are we called from the interrupt handler? */
if (!from_int)
{
e->rx_message = *mp;
e->status |= E1000_READING;
e->rx_size = 0;
assert(e->rx_message.DL_COUNT > 0);
assert(e->rx_message.DL_COUNT < E1000_IOVEC_NR);
}
if (e->status & E1000_READING)
{
/*
* Copy the I/O vector table first.
*/
if ((r = sys_safecopyfrom(e->client, e->rx_message.DL_GRANT, 0,
(vir_bytes) iovec, e->rx_message.DL_COUNT *
sizeof(iovec_s_t), D)) != OK)
{
panic("sys_safecopyfrom() failed: %d", r);
}
/* Find the head, tail and current descriptors. */
head = e1000_reg_read(e, E1000_REG_RDH);
tail = e1000_reg_read(e, E1000_REG_RDT);
cur = (tail + 1) % e->rx_desc_count;
desc = &e->rx_desc[cur];
/*
* Only handle one packet at a time.
*/
if (!(desc->status & E1000_RX_STATUS_EOP))
{
reply(e, OK, FALSE);
return;
}
E1000_DEBUG(4, ("%s: head=%x, tail=%d\n",
e->name, head, tail));
/*
* Copy to vector elements.
*/
for (i = 0; i < e->rx_message.DL_COUNT && bytes < desc->length; i++)
{
size = iovec[i].iov_size < (desc->length - bytes) ?
iovec[i].iov_size : (desc->length - bytes);
E1000_DEBUG(4, ("iovec[%d] = %d[%d]\n",
i, iovec[i].iov_size, size));
if ((r = sys_safecopyto(e->client, iovec[i].iov_grant, 0,
(vir_bytes) e->rx_buffer + bytes +
(cur * E1000_IOBUF_SIZE),
size, D)) != OK)
{
panic("sys_safecopyto() failed: %d", r);
}
bytes += size;
}
desc->status = 0;
/*
* Update state.
*/
e->rx_size = bytes;
e->status |= E1000_RECEIVED;
E1000_DEBUG(2, ("e1000: got %d byte packet\n", e->rx_size));
/* Increment tail. */
e1000_reg_write(e, E1000_REG_RDT, (tail + 1) % e->rx_desc_count);
}
reply(e, OK, FALSE);
}
/*===========================================================================*
* e1000_getstat_s *
*===========================================================================*/
PRIVATE void e1000_getstat_s(mp)
message *mp;
{
int r;
eth_stat_t stats;
e1000_t *e = e1000_port(mp->DL_PORT);
E1000_DEBUG(3, ("e1000: getstat_s()\n"));
stats.ets_recvErr = e1000_reg_read(e, E1000_REG_RXERRC);
stats.ets_sendErr = 0;
stats.ets_OVW = 0;
stats.ets_CRCerr = e1000_reg_read(e, E1000_REG_CRCERRS);
stats.ets_frameAll = 0;
stats.ets_missedP = e1000_reg_read(e, E1000_REG_MPC);
stats.ets_packetR = e1000_reg_read(e, E1000_REG_TPR);
stats.ets_packetT = e1000_reg_read(e, E1000_REG_TPT);
stats.ets_collision = e1000_reg_read(e, E1000_REG_COLC);
stats.ets_transAb = 0;
stats.ets_carrSense = 0;
stats.ets_fifoUnder = 0;
stats.ets_fifoOver = 0;
stats.ets_CDheartbeat = 0;
stats.ets_OWC = 0;
sys_safecopyto(mp->DL_PROC, mp->DL_GRANT, 0, (vir_bytes)&stats,
sizeof(stats), D);
mp->m_type = DL_STAT_REPLY;
mp->DL_PORT = mp->DL_PORT;
mp->DL_STAT = OK;
if((r=send(mp->m_source, mp)) != OK)
panic("e1000_getstat: send() failed: %d", r);
}
/*===========================================================================*
* e1000_getname *
*===========================================================================*/
PRIVATE void e1000_getname(mp)
message *mp;
{
int r;
E1000_DEBUG(3, ("e1000: getname()\n"));
/* Copy our program name. */
strncpy(mp->DL_NAME, progname, sizeof(mp->DL_NAME));
mp->DL_NAME[ sizeof(mp->DL_NAME) - 1 ] = 0;
/* Acknowledge the name request. */
mp->m_type = DL_NAME_REPLY;
if ((r = send(mp->m_source, mp)) != OK)
{
panic("e1000_getname: send() failed: %d", r);
}
}
/*===========================================================================*
* e1000_interrupt *
*===========================================================================*/
PRIVATE void e1000_interrupt(mp)
message *mp;
{
e1000_t *e;
u32_t cause;
unsigned int i;
E1000_DEBUG(3, ("e1000: interrupt\n"));
/*
* Loop all cards. Check for interrupt reason(s).
*/
for (i = 0; i < E1000_PORT_NR; i++)
{
e = e1000_port(i);
/* Re-enable 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)))
{
if (cause & E1000_REG_ICR_LSC)
e1000_link_changed(e);
if (cause & (E1000_REG_ICR_RXO | E1000_REG_ICR_RXT))
e1000_readv_s(&e->rx_message, TRUE);
if ((cause & E1000_REG_ICR_TXQE) ||
(cause & E1000_REG_ICR_TXDW))
e1000_writev_s(&e->tx_message, TRUE);
}
}
}
/*===========================================================================*
* e1000_link_changed *
*===========================================================================*/
PRIVATE int e1000_link_changed(e)
e1000_t *e;
{
E1000_DEBUG(4, ("%s: link_changed()\n", e->name));
return FALSE;
}
/*===========================================================================*
* e1000_stop *
*===========================================================================*/
PRIVATE void e1000_stop()
{
E1000_DEBUG(3, ("e1000: stop()\n"));
exit(EXIT_SUCCESS);
}
/*===========================================================================*
* e1000_port *
*===========================================================================*/
PRIVATE e1000_t * e1000_port(num)
int num;
{
/*
* Is the given port number within the allowed range?
*/
if (num < 0 || num >= E1000_PORT_NR)
{
panic("invalid port number given: %d", num);
}
/*
* The card must be active.
*/
if (!(e1000_table[num].status & E1000_DETECTED))
{
panic("inactive port number given: %d", num);
}
return &e1000_table[num];
}
/*===========================================================================*
* e1000_reg_read *
*===========================================================================*/
PRIVATE uint32_t e1000_reg_read(e, reg)
e1000_t *e;
uint32_t reg;
{
uint32_t value;
/* Assume a sane register. */
assert(reg < 0x1ffff);
/* Read from memory mapped register. */
value = *(u32_t *)(e->regs + reg);
/* Return the result. */
return value;
}
/*===========================================================================*
* e1000_reg_write *
*===========================================================================*/
PRIVATE void e1000_reg_write(e, reg, value)
e1000_t *e;
uint32_t reg;
uint32_t value;
{
/* Assume a sane register. */
assert(reg < 0x1ffff);
/* Write to memory mapped register. */
*(u32_t *)(e->regs + reg) = value;
}
/*===========================================================================*
* e1000_reg_set *
*===========================================================================*/
PRIVATE void e1000_reg_set(e, reg, value)
e1000_t *e;
uint32_t reg;
uint32_t value;
{
uint32_t data;
/* First read the current value. */
data = e1000_reg_read(e, reg);
/* Set value, and write back. */
e1000_reg_write(e, reg, data | value);
}
/*===========================================================================*
* e1000_reg_unset *
*===========================================================================*/
PRIVATE void e1000_reg_unset(e, reg, value)
e1000_t *e;
uint32_t reg;
uint32_t value;
{
uint32_t data;
/* First read the current value. */
data = e1000_reg_read(e, reg);
/* Unset value, and write back. */
e1000_reg_write(e, reg, data & ~value);
}
/*===========================================================================*
* eeprom_eerd *
*===========================================================================*/
PRIVATE u16_t eeprom_eerd(v, reg)
void *v;
int reg;
{
e1000_t *e = (e1000_t *) v;
u16_t data;
/* Request EEPROM read. */
e1000_reg_write(e, E1000_REG_EERD,
(reg << e->eeprom_addr_off) | (E1000_REG_EERD_START));
/* Wait until ready. */
while (!(e1000_reg_read(e, E1000_REG_EERD) &
e->eeprom_done_bit));
/* Fetch data. */
data = (e1000_reg_read(e, E1000_REG_EERD) &
E1000_REG_EERD_DATA) >> 16;
return data;
}
/*===========================================================================*
* eeprom_ich_init *
*===========================================================================*/
PRIVATE int eeprom_ich_init(e)
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."));
goto out;
}
/* 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"));
}
}
out:
return ret_val;
}
/*===========================================================================*
* eeprom_ich_cycle *
*===========================================================================*/
PRIVATE int eeprom_ich_cycle(const 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 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;
}
/*===========================================================================*
* eeprom_ich *
*===========================================================================*/
PRIVATE u16_t eeprom_ich(v, reg)
void *v;
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;
e1000_t *e = (e1000_t *) v;
u16_t data;
E1000_DEBUG(3, ("e1000_read_flash_data_ich8lan"));
if (reg > ICH_FLASH_LINEAR_ADDR_MASK)
goto out;
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(v, 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);
out:
return data;
}
/*===========================================================================*
* reply *
*===========================================================================*/
PRIVATE void reply(e, err, may_block)
e1000_t *e;
int err;
int may_block;
{
message msg;
int r;
/* Only reply to client for read/write request. */
if (!(e->status & E1000_READING ||
e->status & E1000_WRITING))
{
return;
}
/* Construct reply message. */
msg.m_type = DL_TASK_REPLY;
msg.DL_PORT = e - e1000_table;
msg.DL_PROC = e->client;
msg.DL_COUNT = 0;
msg.DL_STAT = 0;
msg.DL_CLCK = 0;
/* Did we successfully receive packet(s)? */
if (e->status & E1000_READING &&
e->status & E1000_RECEIVED)
{
msg.DL_STAT = DL_PACK_RECV;
msg.DL_COUNT = e->rx_size >= ETH_MIN_PACK_SIZE ?
e->rx_size : ETH_MIN_PACK_SIZE;
/* Clear flags. */
e->status &= ~(E1000_READING | E1000_RECEIVED);
}
/* Did we successfully transmit packet(s)? */
if (e->status & E1000_TRANSMIT &&
e->status & E1000_WRITING)
{
msg.DL_STAT = DL_PACK_SEND;
msg.DL_COUNT = 0;
/* Clear flags. */
e->status &= ~(E1000_WRITING | E1000_TRANSMIT);
}
/* Acknowledge to INET. */
if ((r = send(e->client, &msg)) != OK)
{
panic("send() failed: %d", r);
}
}
/*===========================================================================*
* mess_reply *
*===========================================================================*/
PRIVATE void mess_reply(req, reply_mess)
message *req;
message *reply_mess;
{
if (send(req->m_source, reply_mess) != OK)
{
panic("unable to send reply message");
}
}