[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [cdi-devel] [PATCH] Make e1000 work in VirtualBox



Bump, requesting for this to be committed. The mentioned VMWare stuff
may depend on this patch.

Thanks,

Matt

On Sat, Mar 13, 2010 at 7:33 PM, Matthew Iselin <matthew@xxxxxxxxxxxxxx> wrote:
> Hi,
>
> This patch makes the e1000 driver work in VirtualBox. I'm working towards
> getting the driver working in VMWare as well, but VMWare emulates a
> different chip (82545 rather than 82540). Those fixes and adjustments
> will come in a different patch, at a later date.
>
> The biggest change here is that the driver now supports the microwire
> interface for reading from the EEPROM as well as the EERD.
>
> Cheers,
>
> Matt
>
> Signed-off-by: Matthew Iselin <matthew@xxxxxxxxxxxxxx>
> ---
>  e1000/device.c    |  224 +++++++++++++++++++++++++++++++++++++++++++++++++----
>  e1000/device.h    |   22 +++++-
>  3 files changed, 232 insertions(+), 18 deletions(-)
>
> diff --git a/e1000/device.c b/e1000/device.c
> index 1b31987..f1caa1f 100644
> --- a/e1000/device.c
> +++ b/e1000/device.c
> @@ -48,14 +48,210 @@
>  static void e1000_handle_interrupt(struct cdi_device* device);
>  static uint64_t get_mac_address(struct e1000_device* device);
>
> -static uint16_t e1000_eeprom_read(struct e1000_device* device, uint16_t offset)
> +static uint32_t e1000_reg_read(struct e1000_device *device, uint16_t offset)
> +{
> +    return reg_inl(device, offset);
> +}
> +
> +static void e1000_reg_write(struct e1000_device *device, uint16_t offset, uint32_t value)
> +{
> +    reg_outl(device, offset, value);
> +}
> +
> +static void e1000_write_flush(struct e1000_device *device)
> +{
> +    uint32_t temp = e1000_reg_read(device, REG_STATUS);
> +}
> +
> +static void e1000_raise_eeprom_clock(struct e1000_device *device, uint32_t *eecd)
> +{
> +    *eecd |= E1000_EECD_SK;
> +    e1000_reg_write(device, REG_EECD, *eecd);
> +    e1000_write_flush(device);
> +    cdi_sleep_ms(5);
> +}
> +
> +static void e1000_lower_eeprom_clock(struct e1000_device *device, uint32_t *eecd)
> +{
> +    *eecd &= ~E1000_EECD_SK;
> +    e1000_reg_write(device, REG_EECD, *eecd);
> +    e1000_write_flush(device);
> +    cdi_sleep_ms(5);
> +}
> +
> +static void e1000_write_eeprom_bits(struct e1000_device *device, uint16_t data, uint16_t bitcount)
> +{
> +    uint32_t eecd, mask;
> +
> +    mask = 0x1 << (bitcount - 1);
> +    eecd = e1000_reg_read(device, REG_EECD);
> +    eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
> +    do
> +    {
> +        eecd &= ~E1000_EECD_DI;
> +        if(data & mask)
> +            eecd |= E1000_EECD_DI;
> +        e1000_reg_write(device, REG_EECD, eecd);
> +        e1000_write_flush(device);
> +
> +        cdi_sleep_ms(5);
> +
> +        e1000_raise_eeprom_clock(device, &eecd);
> +        e1000_lower_eeprom_clock(device, &eecd);
> +
> +        mask >>= 1;
> +    }
> +    while(mask);
> +
> +    eecd &= ~E1000_EECD_DI;
> +    e1000_reg_write(device, REG_EECD, eecd);
> +}
> +
> +static uint16_t e1000_read_eeprom_bits(struct e1000_device *device)
> +{
> +    uint32_t eecd, i;
> +    uint16_t data;
> +
> +    eecd = e1000_reg_read(device, REG_EECD);
> +    eecd &= ~(E1000_EECD_DO | E1000_EECD_DI);
> +    data = 0;
> +
> +    for(i = 0; i < 16; i++)
> +    {
> +        data <<= 1;
> +        e1000_raise_eeprom_clock(device, &eecd);
> +
> +        eecd = e1000_reg_read(device, REG_EECD);
> +
> +        eecd &= ~E1000_EECD_DI;
> +        if(eecd & E1000_EECD_DO)
> +            data |= 1;
> +
> +        e1000_lower_eeprom_clock(device, &eecd);
> +    }
> +
> +    return data;
> +}
> +
> +static void e1000_prep_eeprom(struct e1000_device *device)
>  {
> -    uint32_t eerd;
> +    uint32_t eecd = e1000_reg_read(device, REG_EECD);
> +
> +    eecd &= ~(E1000_EECD_SK | E1000_EECD_DI);
> +    e1000_reg_write(device, REG_EECD, eecd);
> +
> +    eecd |= E1000_EECD_CS;
> +    e1000_reg_write(device, REG_EECD, eecd);
> +}
> +
> +static void e1000_standby_eeprom(struct e1000_device *device)
> +{
> +    uint32_t eecd = e1000_reg_read(device, REG_EECD);
> +
> +    eecd &= ~(E1000_EECD_CS | E1000_EECD_SK);
> +    e1000_reg_write(device, REG_EECD, eecd);
> +    e1000_write_flush(device);
> +    cdi_sleep_ms(5);
> +
> +    eecd |= E1000_EECD_SK;
> +    e1000_reg_write(device, REG_EECD, eecd);
> +    e1000_write_flush(device);
> +    cdi_sleep_ms(5);
> +
> +    eecd |= E1000_EECD_CS;
> +    e1000_reg_write(device, REG_EECD, eecd);
> +    e1000_write_flush(device);
> +    cdi_sleep_ms(5);
> +
> +    eecd &= ~(E1000_EECD_SK);
> +    e1000_reg_write(device, REG_EECD, eecd);
> +    e1000_write_flush(device);
> +    cdi_sleep_ms(5);
> +}
> +
> +static uint32_t e1000_read_uwire(struct e1000_device *device, uint16_t offset)
> +{
> +    uint32_t eecd, i = 0;
> +    int large_eeprom = 0;
> +
> +    // TODO: check for post-82544 chip, only run this handling if so
> +    eecd = e1000_reg_read(device, REG_EECD);
> +    if(eecd & E1000_EECD_SIZE)
> +        large_eeprom = 1;
> +    eecd |= E1000_EECD_REQ;
> +    e1000_reg_write(device, REG_EECD, eecd);
> +    eecd = e1000_reg_read(device, REG_EECD);
> +    while((!(eecd & E1000_EECD_GNT)) && (i++ < 100))
> +    {
> +        cdi_sleep_ms(1);
> +        eecd = e1000_reg_read(device, REG_EECD);
> +    }
> +    if(!(eecd & E1000_EECD_GNT))
> +    {
> +        eecd &= ~E1000_EECD_REQ;
> +        e1000_reg_write(device, REG_EECD, eecd);
> +        return (uint32_t) -1;
> +    }
> +
> +    e1000_prep_eeprom(device);
> +
> +    e1000_write_eeprom_bits(device, EEPROM_READ_OPCODE, 3);
> +    if(large_eeprom)
> +        e1000_write_eeprom_bits(device, offset, 8);
> +    else
> +        e1000_write_eeprom_bits(device, offset, 6);
> +
> +    uint32_t data = e1000_read_eeprom_bits(device);
> +
> +    e1000_standby_eeprom(device);
> +
> +    // TODO: check for post-82544 chip
> +    eecd = e1000_reg_read(device, REG_EECD);
> +    eecd &= ~E1000_EECD_REQ;
> +    e1000_reg_write(device, REG_EECD, eecd);
> +
> +    return data;
> +}
> +
> +static uint32_t e1000_read_eerd(struct e1000_device *device, uint16_t offset)
> +{
> +    uint32_t eerd, i;
>
>     reg_outl(device, REG_EEPROM_READ, (offset << 8) | EERD_START);
> -    while (((eerd = reg_inl(device, REG_EEPROM_READ)) & EERD_DONE) == 0);
> -    printf("eerd = %8x\n", eerd);
> -    return (eerd >> 16);
> +    for(i = 0; i < 100; i++)
> +    {
> +        eerd = reg_inl(device, REG_EEPROM_READ);
> +        if(eerd & EERD_DONE)
> +            break;
> +        cdi_sleep_ms(1);
> +    }
> +
> +    if(eerd & EERD_DONE)
> +        return (eerd >> 16) & 0xFFFF;
> +    else
> +        return (uint32_t) -1;
> +}
> +
> +static uint16_t e1000_eeprom_read(struct e1000_device* device, uint16_t offset)
> +{
> +    static int eerd_safe = 1;
> +
> +    uint32_t data = 0;
> +    if(eerd_safe)
> +        data = e1000_read_eerd(device, offset);
> +    if(!eerd_safe || (data == ((uint32_t) -1)))
> +    {
> +        eerd_safe = 0;
> +
> +        data = e1000_read_uwire(device, offset);
> +        if(data == ((uint32_t) -1))
> +        {
> +            printf("e1000: couldn't read eeprom via EERD or uwire!");
> +            return 0;
> +        }
> +    }
> +
> +    return (uint16_t) (data & 0xFFFF);
>  }
>
>  static void reset_nic(struct e1000_device* netcard)
> @@ -106,6 +302,9 @@ static void reset_nic(struct e1000_device* netcard)
>     reg_outl(netcard, REG_RECV_ADDR_LIST + 4,
>         ((mac >> 32) & 0xFFFF) | RAH_VALID);
>
> +    netcard->net.mac = mac;
> +    printf("e1000: MAC-Adresse: %012llx\n", (uint64_t) netcard->net.mac);
> +
>     // Rx-Deskriptoren aufsetzen
>     for (i = 0; i < RX_BUFFER_NUM; i++) {
>         netcard->rx_desc[i].length = RX_BUFFER_SIZE;
> @@ -123,10 +322,6 @@ static void reset_nic(struct e1000_device* netcard)
>     netcard->tx_cur_buffer = 0;
>     netcard->rx_cur_buffer = 0;
>
> -    // Interrupts aktivieren
> -    reg_outl(netcard, REG_INTR_MASK_CLR, 0xFFFF);
> -    reg_outl(netcard, REG_INTR_MASK, 0xFFFF);
> -
>     // Rx/Tx aktivieren
>     reg_outl(netcard, REG_RX_CTL, RCTL_ENABLE | RCTL_BROADCAST);
>     reg_outl(netcard, REG_TX_CTL, TCTL_ENABLE | TCTL_PADDING
> @@ -153,7 +348,7 @@ struct cdi_device* e1000_init_device(struct cdi_bus_data* bus_data)
>     struct e1000_device* netcard;
>     struct cdi_mem_area* buf;
>
> -    if (!((pci->vendor_id == 0x8086) && (pci->device_id == 0x100e))) {
> +    if (!((pci->vendor_id == 0x8086) && ((pci->device_id == 0x100e) || (pci->device_id == 0x100f)))) {
>         return NULL;
>     }
>
> @@ -191,11 +386,12 @@ struct cdi_device* e1000_init_device(struct cdi_bus_data* bus_data)
>     printf("e1000: Fuehre Reset der Karte durch\n");
>     reset_nic(netcard);
>
> -    netcard->net.mac = get_mac_address(netcard);
> -    printf("e1000: MAC-Adresse: %012llx\n", (uint64_t) netcard->net.mac);
> -
>     cdi_net_device_init(&netcard->net);
>
> +    // Interrupts aktivieren
> +    reg_outl(netcard, REG_INTR_MASK_CLR, 0xFFFF);
> +    reg_outl(netcard, REG_INTR_MASK, 0xFFFF);
> +
>     return &netcard->net.dev;
>  }
>
> diff --git a/e1000/device.h b/e1000/device.h
> index 2a10365..428edad 100644
> --- a/e1000/device.h
> +++ b/e1000/device.h
> @@ -26,8 +26,8 @@
>  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
>  */
>
> -#ifndef _SIS900_DEVICES_H_
> -#define _SIS900_DEVICES_H_
> +#ifndef _E1000_DEVICE_H_
> +#define _E1000_DEVICE_H_
>
>  #include <stdint.h>
>
> @@ -38,6 +38,8 @@
>
>  enum {
>     REG_CTL             =    0x0,
> +    REG_STATUS          =    0x8,
> +    REG_EECD            =   0x10, /* EEPROM Control */
>     REG_EEPROM_READ     =   0x14, /* EERD */
>     REG_VET             =   0x38, /* VLAN */
>
> @@ -104,6 +106,22 @@ enum {
>  #define EERD_START  (1 <<  0)
>  #define EERD_DONE   (1 <<  4)
>
> +/* EEPROM/Flash Control */
> +#define E1000_EECD_SK        0x00000001 /* EEPROM Clock */
> +#define E1000_EECD_CS        0x00000002 /* EEPROM Chip Select */
> +#define E1000_EECD_DI        0x00000004 /* EEPROM Data In */
> +#define E1000_EECD_DO        0x00000008 /* EEPROM Data Out */
> +#define E1000_EECD_FWE_MASK  0x00000030
> +#define E1000_EECD_FWE_DIS   0x00000010 /* Disable FLASH writes */
> +#define E1000_EECD_FWE_EN    0x00000020 /* Enable FLASH writes */
> +#define E1000_EECD_FWE_SHIFT 4
> +#define E1000_EECD_SIZE      0x00000200 /* EEPROM Size (0=64 word 1=256 word) */
> +#define E1000_EECD_REQ       0x00000040 /* EEPROM Access Request */
> +#define E1000_EECD_GNT       0x00000080 /* EEPROM Access Grant */
> +#define E1000_EECD_PRES      0x00000100 /* EEPROM Present */
> +
> +#define EEPROM_READ_OPCODE  0x6
> +
>  /* Allgemeine Definitionen */
>
>  #define TX_BUFFER_SIZE  2048
> --
> 1.6.4.msysgit.0
>
>