]> rtime.felk.cvut.cz Git - jailhouse.git/blobdiff - inmates/demos/x86/e1000-demo.c
Merge remote-tracking branch 'kiszka/master'
[jailhouse.git] / inmates / demos / x86 / e1000-demo.c
index ab22ab2687364beede68b0884b23221faa0d4c94..e60152f2b7039f34fddd8b220e791eddceb8a8fd 100644 (file)
 
 #define E1000_REG_CTRL         0x0000
 # define E1000_CTRL_LRST       (1 << 3)
-# define E1000_CTRL_ASDE       (1 << 5)
 # define E1000_CTRL_SLU                (1 << 6)
-# define E1000_CTRL_FRCSPD     (1 << 12)
+# define E1000_CTRL_FRCSPD     (1 << 11)
 # define E1000_CTRL_RST                (1 << 26)
 #define E1000_REG_STATUS       0x0008
 # define E1000_STATUS_LU       (1 << 1)
+# define E1000_STATUS_SPEEDSHFT        6
+# define E1000_STATUS_SPEED    (3 << E1000_STATUS_SPEEDSHFT)
 #define E1000_REG_EERD         0x0014
 # define E1000_EERD_START      (1 << 0)
 # define E1000_EERD_DONE       (1 << 4)
 # define E1000_EERD_ADDR_SHIFT 8
 # define E1000_EERD_DATA_SHIFT 16
+#define E1000_REG_MDIC         0x0020
+# define E1000_MDIC_REGADD_SHFT        16
+# define E1000_MDIC_PHYADD     (0x1 << 21)
+# define E1000_MDIC_OP_WRITE   (0x1 << 26)
+# define E1000_MDIC_OP_READ    (0x2 << 26)
+# define E1000_MDIC_READY      (0x1 << 28)
 #define E1000_REG_RCTL         0x0100
 # define E1000_RCTL_EN         (1 << 1)
 # define E1000_RCTL_BAM                (1 << 15)
 #define E1000_REG_RDLEN                0x2808
 #define E1000_REG_RDH          0x2810
 #define E1000_REG_RDT          0x2818
+#define E1000_REG_RXDCTL       0x2828
+# define E1000_RXDCTL_ENABLE   (1 << 25)
 #define E1000_REG_TDBAL                0x3800
 #define E1000_REG_TDBAH                0x3804
 #define E1000_REG_TDLEN                0x3808
 #define E1000_REG_TDH          0x3810
 #define E1000_REG_TDT          0x3818
+#define E1000_REG_TXDCTL       0x3828
+# define E1000_TXDCTL_ENABLE   (1 << 25)
 #define E1000_REG_RAL          0x5400
 #define E1000_REG_RAH          0x5404
 # define E1000_RAH_AV          (1 << 31)
 
+#define E1000_PHY_CTRL         0
+# define E1000_PHYC_POWER_DOWN (1 << 11)
+
 struct eth_header {
        u8      dst[6];
        u8      src[6];
@@ -117,13 +131,39 @@ struct e1000_txd {
 #define RX_BUFFER_SIZE         2048
 #define TX_DESCRIPTORS         8
 
+static const char *speed_info[] = { "10", "100", "1000", "1000" };
+
 static void *mmiobar;
 static u8 buffer[RX_DESCRIPTORS * RX_BUFFER_SIZE];
-static struct e1000_rxd rx_ring[RX_DESCRIPTORS];
-static struct e1000_txd tx_ring[TX_DESCRIPTORS];
+static struct e1000_rxd rx_ring[RX_DESCRIPTORS] __attribute__((aligned(128)));
+static struct e1000_txd tx_ring[TX_DESCRIPTORS] __attribute__((aligned(128)));
 static unsigned int rx_idx, tx_idx;
 static struct eth_header tx_packet;
 
+static u16 phy_read(unsigned int reg)
+{
+       u32 val;
+
+       mmio_write32(mmiobar + E1000_REG_MDIC,
+                    (reg << E1000_MDIC_REGADD_SHFT) |
+                    E1000_MDIC_PHYADD | E1000_MDIC_OP_READ);
+       do {
+               val = mmio_read32(mmiobar + E1000_REG_MDIC);
+               cpu_relax();
+       } while (!(val & E1000_MDIC_READY));
+
+       return (u16)val;
+}
+
+static void phy_write(unsigned int reg, u16 val)
+{
+       mmio_write32(mmiobar + E1000_REG_MDIC,
+                    val | (reg << E1000_MDIC_REGADD_SHFT) |
+                    E1000_MDIC_PHYADD | E1000_MDIC_OP_WRITE);
+       while (!(mmio_read32(mmiobar + E1000_REG_MDIC) & E1000_MDIC_READY))
+               cpu_relax();
+}
+
 static void send_packet(void *buffer, unsigned int size)
 {
        unsigned int idx = tx_idx;
@@ -174,7 +214,6 @@ void inmate_main(void)
        int bdf;
 
        printk_uart_base = UART_BASE;
-       pm_timer_init();
 
        bdf = pci_find_device(PCI_ID_ANY, PCI_ID_ANY, 0);
        if (bdf < 0) {
@@ -201,14 +240,22 @@ void inmate_main(void)
 
        val = mmio_read32(mmiobar + E1000_REG_CTRL);
        val &= ~(E1000_CTRL_LRST | E1000_CTRL_FRCSPD);
-       val |= E1000_CTRL_ASDE | E1000_CTRL_SLU;
+       val |= E1000_CTRL_SLU;
        mmio_write32(mmiobar + E1000_REG_CTRL, val);
-       printk("Reset done, waiting for link...");
 
+       /* power up again in case the previous user turned it off */
+       phy_write(E1000_PHY_CTRL,
+                 phy_read(E1000_PHY_CTRL) & ~E1000_PHYC_POWER_DOWN);
+
+       printk("Waiting for link...");
        while (!(mmio_read32(mmiobar + E1000_REG_STATUS) & E1000_STATUS_LU))
                cpu_relax();
        printk(" ok\n");
 
+       val = mmio_read32(mmiobar + E1000_REG_STATUS) & E1000_STATUS_SPEED;
+       val >>= E1000_STATUS_SPEEDSHFT;
+       printk("Link speed: %s Mb/s\n", speed_info[val]);
+
        if (mmio_read32(mmiobar + E1000_REG_RAH) & E1000_RAH_AV) {
                *(u32 *)mac = mmio_read32(mmiobar + E1000_REG_RAL);
                *(u16 *)&mac[4] = mmio_read32(mmiobar + E1000_REG_RAH);
@@ -239,18 +286,24 @@ void inmate_main(void)
        mmio_write32(mmiobar + E1000_REG_RDBAH, 0);
        mmio_write32(mmiobar + E1000_REG_RDLEN, sizeof(rx_ring));
        mmio_write32(mmiobar + E1000_REG_RDH, 0);
-       mmio_write32(mmiobar + E1000_REG_RDT, RX_DESCRIPTORS - 1);
+       mmio_write32(mmiobar + E1000_REG_RDT, 0);
+       mmio_write32(mmiobar + E1000_REG_RXDCTL,
+               mmio_read32(mmiobar + E1000_REG_RXDCTL) | E1000_RXDCTL_ENABLE);
 
        val = mmio_read32(mmiobar + E1000_REG_RCTL);
        val |= E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_BSIZE_2048 |
                E1000_RCTL_SECRC;
        mmio_write32(mmiobar + E1000_REG_RCTL, val);
 
+       mmio_write32(mmiobar + E1000_REG_RDT, RX_DESCRIPTORS - 1);
+
        mmio_write32(mmiobar + E1000_REG_TDBAL, (unsigned long)&tx_ring);
        mmio_write32(mmiobar + E1000_REG_TDBAH, 0);
        mmio_write32(mmiobar + E1000_REG_TDLEN, sizeof(tx_ring));
        mmio_write32(mmiobar + E1000_REG_TDH, 0);
        mmio_write32(mmiobar + E1000_REG_TDT, 0);
+       mmio_write32(mmiobar + E1000_REG_TXDCTL,
+               mmio_read32(mmiobar + E1000_REG_TXDCTL) | E1000_TXDCTL_ENABLE);
 
        val = mmio_read32(mmiobar + E1000_REG_TCTL);
        val |= E1000_TCTL_EN | E1000_TCTL_PSP | E1000_TCTL_CT_DEF |