[PATCH 1/6] inmates: e1000-demo: Ensure ring alignment requirements on newer NICs

8 views
Skip to first unread message

Jan Kiszka

unread,
Feb 4, 2016, 1:41:24 AM2/4/16
to jailho...@googlegroups.com
The Intel 82575 and newer NICs require 128-byte alignment of the RX and
TX rings.

Signed-off-by: Jan Kiszka <jan.k...@siemens.com>
---
inmates/demos/x86/e1000-demo.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/inmates/demos/x86/e1000-demo.c b/inmates/demos/x86/e1000-demo.c
index d7c2a66..7273f36 100644
--- a/inmates/demos/x86/e1000-demo.c
+++ b/inmates/demos/x86/e1000-demo.c
@@ -136,8 +136,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 unsigned int phyadd;
--
2.1.4

Jan Kiszka

unread,
Feb 4, 2016, 1:41:24 AM2/4/16
to jailho...@googlegroups.com
These patches improve x86 inmated "e1000-demo". It now works with more
recent Intel NICs, namely those that Linux addresses via the igd driver.

Jan

Jan Kiszka (6):
inmates: e1000-demo: Ensure ring alignment requirements on newer NICs
inmates: e1000-demo: Hard-wire PHY address
inmates: e1000-demo: Write RX tail only after enabling the queue
inmates: e1000-demo: Fix FRCSPD bit definition for control register
inmates: e1000-demo: Do not set ASDE bit
inmates: e1000-demo: Enable queues explicitly

inmates/demos/x86/e1000-demo.c | 36 ++++++++++++++++++------------------
1 file changed, 18 insertions(+), 18 deletions(-)

--
2.1.4

Jan Kiszka

unread,
Feb 4, 2016, 1:41:24 AM2/4/16
to jailho...@googlegroups.com
The 82575 ignores all writes prior to enabling the queue or the complete
receiver. Reorder writes, clearing the tail first - just in case.

Signed-off-by: Jan Kiszka <jan.k...@siemens.com>
---
inmates/demos/x86/e1000-demo.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/inmates/demos/x86/e1000-demo.c b/inmates/demos/x86/e1000-demo.c
index 6aaa102..abb11d0 100644
--- a/inmates/demos/x86/e1000-demo.c
+++ b/inmates/demos/x86/e1000-demo.c
@@ -283,13 +283,15 @@ 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);

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));
--
2.1.4

Jan Kiszka

unread,
Feb 4, 2016, 1:41:24 AM2/4/16
to jailho...@googlegroups.com
It's bit 11, in fact. Bit 12 is FRCDPLX which is cleared on reset.

Signed-off-by: Jan Kiszka <jan.k...@siemens.com>
---
inmates/demos/x86/e1000-demo.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/inmates/demos/x86/e1000-demo.c b/inmates/demos/x86/e1000-demo.c
index abb11d0..2f3402b 100644
--- a/inmates/demos/x86/e1000-demo.c
+++ b/inmates/demos/x86/e1000-demo.c
@@ -27,7 +27,7 @@
# 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)
--
2.1.4

Jan Kiszka

unread,
Feb 4, 2016, 1:41:25 AM2/4/16
to jailho...@googlegroups.com
ASDE is apparently not needed on older NICs but caused troubles on newer
ones like 82575. Remove it.

Signed-off-by: Jan Kiszka <jan.k...@siemens.com>
---
inmates/demos/x86/e1000-demo.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/inmates/demos/x86/e1000-demo.c b/inmates/demos/x86/e1000-demo.c
index 2f3402b..9d2d779 100644
--- a/inmates/demos/x86/e1000-demo.c
+++ b/inmates/demos/x86/e1000-demo.c
@@ -25,7 +25,6 @@

#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 << 11)
# define E1000_CTRL_RST (1 << 26)
@@ -237,7 +236,7 @@ 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);

/* power up again in case the previous user turned it off */
--
2.1.4

Jan Kiszka

unread,
Feb 4, 2016, 1:41:25 AM2/4/16
to jailho...@googlegroups.com
Newer NICs require us to enable the RX and TX queue. Although they
should be on after reset, at least the I350 refuses to work otherwise.
As the related bit is harmless or even unused on older NICs, do this
unconditionally (just like ipxe does).

Signed-off-by: Jan Kiszka <jan.k...@siemens.com>
---
inmates/demos/x86/e1000-demo.c | 8 ++++++++
1 file changed, 8 insertions(+)

diff --git a/inmates/demos/x86/e1000-demo.c b/inmates/demos/x86/e1000-demo.c
index 9d2d779..e60152f 100644
--- a/inmates/demos/x86/e1000-demo.c
+++ b/inmates/demos/x86/e1000-demo.c
@@ -62,11 +62,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)
@@ -283,6 +287,8 @@ void inmate_main(void)
mmio_write32(mmiobar + E1000_REG_RDLEN, sizeof(rx_ring));
mmio_write32(mmiobar + E1000_REG_RDH, 0);
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 |
@@ -296,6 +302,8 @@ void inmate_main(void)
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 |
--
2.1.4

Jan Kiszka

unread,
Feb 4, 2016, 1:41:29 AM2/4/16
to jailho...@googlegroups.com
All known e1000-compatible cards have their PHYs at address 1. Searching
for them does not work reliably, so simply hard-wire the address.

Signed-off-by: Jan Kiszka <jan.k...@siemens.com>
---
inmates/demos/x86/e1000-demo.c | 15 +++------------
1 file changed, 3 insertions(+), 12 deletions(-)

diff --git a/inmates/demos/x86/e1000-demo.c b/inmates/demos/x86/e1000-demo.c
index 7273f36..6aaa102 100644
--- a/inmates/demos/x86/e1000-demo.c
+++ b/inmates/demos/x86/e1000-demo.c
@@ -40,7 +40,7 @@
# define E1000_EERD_DATA_SHIFT 16
#define E1000_REG_MDIC 0x0020
# define E1000_MDIC_REGADD_SHFT 16
-# define E1000_MDIC_PHYADD_SHFT 21
+# 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)
@@ -72,12 +72,8 @@
#define E1000_REG_RAH 0x5404
# define E1000_RAH_AV (1 << 31)

-#define E1000_MAX_PHYADD 7
-
#define E1000_PHY_CTRL 0
# define E1000_PHYC_POWER_DOWN (1 << 11)
-#define E1000_PHY_PSTATUS 1
-#define E1000_PHY_ID1 2

struct eth_header {
u8 dst[6];
@@ -140,7 +136,6 @@ 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 unsigned int phyadd;

static u16 phy_read(unsigned int reg)
{
@@ -148,7 +143,7 @@ static u16 phy_read(unsigned int reg)

mmio_write32(mmiobar + E1000_REG_MDIC,
(reg << E1000_MDIC_REGADD_SHFT) |
- (phyadd << E1000_MDIC_PHYADD_SHFT) | E1000_MDIC_OP_READ);
+ E1000_MDIC_PHYADD | E1000_MDIC_OP_READ);
do {
val = mmio_read32(mmiobar + E1000_REG_MDIC);
cpu_relax();
@@ -161,7 +156,7 @@ static void phy_write(unsigned int reg, u16 val)
{
mmio_write32(mmiobar + E1000_REG_MDIC,
val | (reg << E1000_MDIC_REGADD_SHFT) |
- (phyadd << E1000_MDIC_PHYADD_SHFT) | E1000_MDIC_OP_WRITE);
+ E1000_MDIC_PHYADD | E1000_MDIC_OP_WRITE);
while (!(mmio_read32(mmiobar + E1000_REG_MDIC) & E1000_MDIC_READY))
cpu_relax();
}
@@ -245,10 +240,6 @@ void inmate_main(void)
val |= E1000_CTRL_ASDE | E1000_CTRL_SLU;
mmio_write32(mmiobar + E1000_REG_CTRL, val);

- for (phyadd = 0; phyadd <= E1000_MAX_PHYADD; phyadd++)
- if (phy_read(E1000_PHY_ID1) != 0)
- break;
- printk("PHY address: %d\n", phyadd);
/* 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);
--
2.1.4

Reply all
Reply to author
Forward
0 new messages