[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [cdi-devel] [PATCH] Make e1000 work in VirtualBox
- Date: Wed, 11 Aug 2010 15:31:38 +1000
- From: Matthew Iselin <matthew@xxxxxxxxxxxxxx>
- To: Common Driver Interface development list <cdi-devel@xxxxxxxxxx>
- Subject: Re: [cdi-devel] [PATCH] Make e1000 work in VirtualBox
- Message-id: <AANLkTi=E9b5Z-1ymqA1SpyUn3Z3yuXwOW951=kfZm+zR@mail.gmail.com>
- In-reply-to: <AANLkTi=eMwYWOviN=2aGC9fOFib_c68bgQF58hF=5VFr@mail.gmail.com>
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
>
>