[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[cdi-devel] [PATCH v2] Make e1000 work in VirtualBox
- Date: Mon, 16 Aug 2010 21:16:11 +1000
- From: Matthew Iselin <matthew@xxxxxxxxxxxxxx>
- To: Common Driver Interface development list <cdi-devel@xxxxxxxxxx>
- Subject: [cdi-devel] [PATCH v2] Make e1000 work in VirtualBox
- Message-id: <AANLkTin=y1GBfsFA3RQAz40e4JWSo27UArf=QVXtWj0R@mail.gmail.com>
- In-reply-to: <AANLkTikP9Xt5AkPXy3FiHXPzjiEpkEaz7gB72rXSsdnK@mail.gmail.com>
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.
This is the second version of this patch, and fixes the "unused
variable" error that comes up for some environments.
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)
+{
+ 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