Skip to content

Commit 37f9aed

Browse files
jmichalski-antcfriedt
authored andcommitted
net: ethernet: e1000: add queue support
Before this commit size of rx and tx queues was set to 1, which is out of spec. This commit adds queue logic, ability to set their size and exposes configuration options w.r.t rx queue interrupts Signed-off-by: Jakub Michalski <[email protected]>
1 parent 3e82d7c commit 37f9aed

File tree

4 files changed

+104
-42
lines changed

4 files changed

+104
-42
lines changed

drivers/ethernet/Kconfig.e1000

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,16 @@ config ETH_E1000_PTP_CLOCK_SRC_HZ
4343
Set the frequency in Hz sourced to the PTP timer.
4444
If the value is set properly, the timer will be accurate.
4545

46+
config ETH_E1000_RX_QUEUE_SIZE
47+
int "Size of receive queue"
48+
default 8
49+
help
50+
Sets size of receive descriptor queue. It has to be a multiple of 8.
51+
52+
config ETH_E1000_TX_QUEUE_SIZE
53+
int "Size of transmit queue"
54+
default 8
55+
help
56+
Sets size of transmit descriptor queue. It has to be a multiple of 8.
57+
4658
endif # ETH_E1000

drivers/ethernet/eth_e1000.c

Lines changed: 53 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ static const char *e1000_reg_to_string(enum e1000_reg_t r)
6161
_(TDT);
6262
_(RAL);
6363
_(RAH);
64+
_(ITR);
6465
}
6566
#undef _
6667
LOG_ERR("Unsupported register: 0x%x", r);
@@ -103,31 +104,35 @@ static int e1000_tx(struct e1000_dev *dev, void *buf, size_t len)
103104
{
104105
hexdump(buf, len, "%zu byte(s)", len);
105106

106-
dev->tx.addr = POINTER_TO_INT(buf);
107-
dev->tx.len = len;
108-
dev->tx.cmd = TDESC_EOP | TDESC_RS;
107+
dev->tx[dev->next_tx_desc].addr = POINTER_TO_INT(buf);
108+
dev->tx[dev->next_tx_desc].len = len;
109+
dev->tx[dev->next_tx_desc].cmd = TDESC_EOP | TDESC_RS;
110+
dev->tx[dev->next_tx_desc].sta = 0;
109111

110-
iow32(dev, TDT, 1);
112+
uint32_t old_tx_desc = dev->next_tx_desc;
111113

112-
while (!(dev->tx.sta)) {
114+
dev->next_tx_desc = (dev->next_tx_desc + 1) % CONFIG_ETH_E1000_TX_QUEUE_SIZE;
115+
iow32(dev, TDT, dev->next_tx_desc);
116+
117+
while (!(dev->tx[old_tx_desc].sta)) {
113118
k_yield();
114119
}
115120

116-
LOG_DBG("tx.sta: 0x%02hx", dev->tx.sta);
121+
LOG_DBG("tx.sta: 0x%02hx", dev->tx[old_tx_desc].sta);
117122

118-
return (dev->tx.sta & TDESC_STA_DD) ? 0 : -EIO;
123+
return (dev->tx[old_tx_desc].sta & TDESC_STA_DD) ? 0 : -EIO;
119124
}
120125

121126
static int e1000_send(const struct device *ddev, struct net_pkt *pkt)
122127
{
123128
struct e1000_dev *dev = ddev->data;
124129
size_t len = net_pkt_get_len(pkt);
125130

126-
if (net_pkt_read(pkt, dev->txb, len)) {
131+
if (net_pkt_read(pkt, dev->txb[dev->next_tx_desc], len)) {
127132
return -EIO;
128133
}
129134

130-
return e1000_tx(dev, dev->txb, len);
135+
return e1000_tx(dev, dev->txb[dev->next_tx_desc], len);
131136
}
132137

133138
static struct net_pkt *e1000_rx(struct e1000_dev *dev)
@@ -136,19 +141,18 @@ static struct net_pkt *e1000_rx(struct e1000_dev *dev)
136141
void *buf;
137142
ssize_t len;
138143

139-
LOG_DBG("rx.sta: 0x%02hx", dev->rx.sta);
144+
LOG_DBG("rx.sta: 0x%02hx", dev->rx[dev->next_rx_desc].sta);
140145

141-
if (!(dev->rx.sta & RDESC_STA_DD)) {
142-
LOG_ERR("RX descriptor not ready");
143-
goto out;
146+
if (!(dev->rx[dev->next_rx_desc].sta & RDESC_STA_DD)) {
147+
return NULL;
144148
}
145149

146-
buf = INT_TO_POINTER((uint32_t)dev->rx.addr);
147-
len = dev->rx.len - 4;
150+
buf = INT_TO_POINTER((uint32_t)dev->rx[dev->next_rx_desc].addr);
151+
len = dev->rx[dev->next_rx_desc].len - 4;
148152

149153
if (len <= 0) {
150-
LOG_ERR("Invalid RX descriptor length: %hu", dev->rx.len);
151-
goto out;
154+
LOG_ERR("Invalid RX descriptor length: %hu", dev->rx[dev->next_rx_desc].len);
155+
goto err;
152156
}
153157

154158
hexdump(buf, len, "%zd byte(s)", len);
@@ -157,16 +161,24 @@ static struct net_pkt *e1000_rx(struct e1000_dev *dev)
157161
K_NO_WAIT);
158162
if (!pkt) {
159163
LOG_ERR("Out of buffers");
160-
goto out;
164+
goto err;
161165
}
162166

163167
if (net_pkt_write(pkt, buf, len)) {
164168
LOG_ERR("Out of memory for received frame");
165169
net_pkt_unref(pkt);
166170
pkt = NULL;
171+
} else {
172+
goto out;
167173
}
168174

175+
err:
176+
eth_stats_update_errors_rx(get_iface(dev));
169177
out:
178+
dev->rx[dev->next_rx_desc].sta = 0;
179+
iow32(dev, RDT, dev->next_rx_desc);
180+
dev->next_rx_desc = (dev->next_rx_desc + 1) % CONFIG_ETH_E1000_RX_QUEUE_SIZE;
181+
170182
return pkt;
171183
}
172184

@@ -177,16 +189,14 @@ static void e1000_isr(const struct device *ddev)
177189

178190
icr &= ~(ICR_TXDW | ICR_TXQE);
179191

180-
if (icr & ICR_RXO) {
181-
struct net_pkt *pkt = e1000_rx(dev);
182-
183-
icr &= ~ICR_RXO;
192+
if (icr & (ICR_RXO | ICR_RXDMT0 | ICR_RXT0)) {
193+
struct net_pkt *pkt = NULL;
184194

185-
if (pkt) {
195+
while ((pkt = e1000_rx(dev))) {
186196
net_recv_data(get_iface(dev), pkt);
187-
} else {
188-
eth_stats_update_errors_rx(get_iface(dev));
189197
}
198+
199+
icr &= ~(ICR_RXO | ICR_RXDMT0 | ICR_RXT0);
190200
}
191201

192202
if (icr) {
@@ -213,30 +223,34 @@ int e1000_probe(const struct device *ddev)
213223
device_map(&dev->address, mbar.phys_addr, mbar.size,
214224
K_MEM_CACHE_NONE);
215225

216-
/* Setup TX descriptor */
226+
/* Setup TX descriptors */
217227

218-
iow32(dev, TDBAL, (uint32_t)POINTER_TO_UINT(&dev->tx));
219-
iow32(dev, TDBAH, (uint32_t)((POINTER_TO_UINT(&dev->tx) >> 16) >> 16));
220-
iow32(dev, TDLEN, 1*16);
228+
iow32(dev, TDBAL, (uint32_t)POINTER_TO_UINT(&dev->tx[0]));
229+
iow32(dev, TDBAH, (uint32_t)((POINTER_TO_UINT(&dev->tx[0]) >> 16) >> 16));
230+
iow32(dev, TDLEN, (uint32_t)(CONFIG_ETH_E1000_TX_QUEUE_SIZE * sizeof(struct e1000_tx)));
221231

222232
iow32(dev, TDH, 0);
223233
iow32(dev, TDT, 0);
234+
dev->next_tx_desc = 0;
224235

225236
iow32(dev, TCTL, TCTL_EN);
226237

227-
/* Setup RX descriptor */
238+
/* Setup RX descriptors */
228239

229-
dev->rx.addr = POINTER_TO_INT(dev->rxb);
230-
dev->rx.len = sizeof(dev->rxb);
240+
for (int i = 0; i < CONFIG_ETH_E1000_RX_QUEUE_SIZE; i++) {
241+
dev->rx[i].addr = POINTER_TO_INT(dev->rxb[i]);
242+
dev->rx[i].len = sizeof(dev->rxb[i]);
243+
}
231244

232-
iow32(dev, RDBAL, (uint32_t)POINTER_TO_UINT(&dev->rx));
233-
iow32(dev, RDBAH, (uint32_t)((POINTER_TO_UINT(&dev->rx) >> 16) >> 16));
234-
iow32(dev, RDLEN, 1*16);
245+
iow32(dev, RDBAL, (uint32_t)POINTER_TO_UINT(&dev->rx[0]));
246+
iow32(dev, RDBAH, (uint32_t)((POINTER_TO_UINT(&dev->rx[0]) >> 16) >> 16));
247+
iow32(dev, RDLEN, (uint32_t)(CONFIG_ETH_E1000_RX_QUEUE_SIZE * sizeof(struct e1000_rx)));
235248

236249
iow32(dev, RDH, 0);
237-
iow32(dev, RDT, 1);
250+
iow32(dev, RDT, CONFIG_ETH_E1000_RX_QUEUE_SIZE - 1);
251+
dev->next_rx_desc = 0;
238252

239-
iow32(dev, IMS, IMS_RXO);
253+
iow32(dev, IMS, IMS_RXDMT0 | IMS_RXO | IMS_RXT0);
240254

241255
ral = ior32(dev, RAL);
242256
rah = ior32(dev, RAH);
@@ -312,7 +326,8 @@ static const struct ethernet_api e1000_api = {
312326
\
313327
irq_enable(DT_INST_IRQN(inst)); \
314328
iow32(dev, CTRL, CTRL_SLU); /* Set link up */ \
315-
iow32(dev, RCTL, RCTL_EN | RCTL_MPE); \
329+
iow32(dev, RCTL, RCTL_EN | RCTL_MPE | DT_INST_PROP(inst, rdmts) << RDMTS_OFFSET); \
330+
iow32(dev, ITR, DT_INST_PROP(inst, itr) & (uint32_t)GENMASK(15, 0)); \
316331
} \
317332
\
318333
static const struct e1000_config config_##inst = { \

drivers/ethernet/eth_e1000_priv.h

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,13 @@ extern "C" {
1818

1919
#define ICR_TXDW (1) /* Transmit Descriptor Written Back */
2020
#define ICR_TXQE (1 << 1) /* Transmit Queue Empty */
21+
#define ICR_RXDMT0 (1 << 4) /* Receive Descriptor Minimum Threshold */
2122
#define ICR_RXO (1 << 6) /* Receiver Overrun */
23+
#define ICR_RXT0 (1 << 7) /* Receiver Timer */
2224

25+
#define IMS_RXDMT0 (1 << 4) /* Receive Descriptor Minimum Threshold */
2326
#define IMS_RXO (1 << 6) /* Receiver FIFO Overrun */
27+
#define IMS_RXT0 (1 << 7) /* Receiver Timer */
2428

2529
#define RCTL_MPE (1 << 4) /* Multicast Promiscuous Enabled */
2630

@@ -32,9 +36,12 @@ extern "C" {
3236

3337
#define ETH_ALEN 6 /* TODO: Add a global reusable definition in OS */
3438

39+
#define RDMTS_OFFSET 8
40+
3541
enum e1000_reg_t {
3642
CTRL = 0x0000, /* Device Control */
3743
ICR = 0x00C0, /* Interrupt Cause Read */
44+
ITR = 0x00C4, /* Interrupt Throttling Rate */
3845
ICS = 0x00C8, /* Interrupt Cause Set */
3946
IMS = 0x00D0, /* Interrupt Mask Set */
4047
RCTL = 0x0100, /* Receive Control */
@@ -75,10 +82,13 @@ struct e1000_rx {
7582
};
7683

7784
struct e1000_dev {
78-
volatile struct e1000_tx tx __aligned(16);
79-
volatile struct e1000_rx rx __aligned(16);
85+
volatile struct e1000_tx tx[CONFIG_ETH_E1000_TX_QUEUE_SIZE] __aligned(16);
86+
volatile struct e1000_rx rx[CONFIG_ETH_E1000_RX_QUEUE_SIZE] __aligned(16);
8087
mm_reg_t address;
8188

89+
uint32_t next_rx_desc;
90+
uint32_t next_tx_desc;
91+
8292
/* BDF & DID/VID */
8393
struct pcie_dev *pcie;
8494

@@ -88,8 +98,8 @@ struct e1000_dev {
8898
*/
8999
struct net_if *iface;
90100
uint8_t mac[ETH_ALEN];
91-
uint8_t txb[NET_ETH_MTU];
92-
uint8_t rxb[NET_ETH_MTU];
101+
uint8_t txb[CONFIG_ETH_E1000_TX_QUEUE_SIZE][NET_ETH_MTU];
102+
uint8_t rxb[CONFIG_ETH_E1000_RX_QUEUE_SIZE][NET_ETH_MTU];
93103
#if defined(CONFIG_ETH_E1000_PTP_CLOCK)
94104
const struct device *ptp_clock;
95105
double clk_ratio;

dts/bindings/ethernet/intel,e1000.yaml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,28 @@ include: [base.yaml, pcie-device.yaml]
1010
properties:
1111
interrupts:
1212
required: true
13+
14+
rdmts:
15+
type: int
16+
default: 0
17+
enum:
18+
- 0
19+
- 1
20+
- 2
21+
description: |
22+
Receive Descriptor Minimum Threshold Size
23+
Controls when RXDMT0 interrupt is set.
24+
0: interrupt set when 1/2 of RDLEN is free
25+
1: interrupt set when 1/4 of RDLEN is free
26+
2: interrupt set when 1/8 of RDLEN is free
27+
The default value is the hardware reset value
28+
29+
itr:
30+
type: int
31+
default: 0
32+
description: |
33+
Interrupt Throttling Rate
34+
Controls inter-interrupt delay. Non-zero value
35+
enables it and adjusts the interval in 256ns
36+
increments. The maximum value is 2^16 - 1.
37+
The default value is the hardware reset value

0 commit comments

Comments
 (0)