From: Helge Deller <deller@kernel.org>
To: qemu-devel@nongnu.org
Cc: Keith Monahan <keith@techtravels.org>,
Richard Henderson <richard.henderson@linaro.org>,
Helge Deller <deller@gmx.de>
Subject: [PULL v2 4/8] i82596: Implement 82596CA big-endian mode (SYSBUS bit 7)
Date: Thu, 5 Nov 2026 23:31:18 +0100 [thread overview]
Message-ID: <20261105223122.8729-5-deller@kernel.org> (raw)
In-Reply-To: <20261105223122.8729-1-deller@kernel.org>
From: Helge Deller <deller@gmx.de>
NetBSD runs the 82596CA chip in big-endian mode, which means the SYSBUS bit #7
is set, and pointers need to be read as big-endian 32-bit pointer values.
Increment the error counters at offsets 12-32 of the SCB live in memory.
Noticed-by: Keith Monahan <keith@techtravels.org>
Signed-off-by: Helge Deller <deller@gmx.de>
---
hw/net/i82596.c | 118 +++++++++++++++++++++++++++++-------------------
hw/net/i82596.h | 3 ++
2 files changed, 74 insertions(+), 47 deletions(-)
diff --git a/hw/net/i82596.c b/hw/net/i82596.c
index 37ce20efb1..a518aa7696 100644
--- a/hw/net/i82596.c
+++ b/hw/net/i82596.c
@@ -221,39 +221,78 @@ static void set_uint32(uint32_t addr, uint32_t val)
set_uint16(addr + 2, val >> 16);
}
+/*
+ * Address fields of the SCB, command blocks and RX/TX descriptors. In
+ * big-endian mode (SYSBUS BE, 82596CA) the chip reads them as 32-bit
+ * big-endian words; otherwise as two 16-bit halves, low half first. The
+ * ISCP and SCB addresses and the SCB counters are always two halves.
+ */
+#define I596_SYSBUS_BE 0x80
+
+static uint32_t get_addr(I82596State *s, uint32_t addr)
+{
+ if (s->sysbus & I596_SYSBUS_BE) {
+ return ldl_be_phys(&address_space_memory, addr);
+ }
+ return get_uint32(addr);
+}
+
+static void set_addr(I82596State *s, uint32_t addr, uint32_t val)
+{
+ if (s->sysbus & I596_SYSBUS_BE) {
+ stl_be_phys(&address_space_memory, addr, val);
+ } else {
+ set_uint32(addr, val);
+ }
+}
+
+/* SCB error counters (linear mode), counted in memory like the chip does */
+#define SCB_CRC_ERRS 12
+#define SCB_ALIGN_ERRS 16
+#define SCB_RESOURCE_ERRS 20
+#define SCB_OVERRUN_ERRS 24
+#define SCB_RCVCDT_ERRS 28
+#define SCB_SHORT_ERRS 32
+
+static void i82596_count_error(I82596State *s, int offset)
+{
+ if (s->scb) {
+ set_uint32(s->scb + offset, get_uint32(s->scb + offset) + 1);
+ }
+}
+
/* Centralized error detection and update mechanism */
static void i82596_record_error(I82596State *s, uint16_t error_type, bool is_tx)
{
if (is_tx) {
if (error_type & TX_ABORTED_ERRORS) {
s->tx_aborted_errors++;
- set_uint32(s->scb + 28, s->tx_aborted_errors);
}
} else {
if (error_type & RX_CRC_ERRORS) {
s->crc_err++;
- set_uint32(s->scb + 16, s->crc_err);
+ i82596_count_error(s, SCB_CRC_ERRS);
}
if (error_type & (RX_LENGTH_ERRORS | RX_LENGTH_ERRORS_ALT |
RX_FRAME_ERRORS)) {
s->align_err++;
- set_uint32(s->scb + 18, s->align_err);
+ i82596_count_error(s, SCB_ALIGN_ERRS);
}
if (error_type & RFD_STATUS_NOBUFS) {
s->resource_err++;
- set_uint32(s->scb + 20, s->resource_err);
+ i82596_count_error(s, SCB_RESOURCE_ERRS);
}
if (error_type & (RX_OVER_ERRORS | RX_FIFO_ERRORS)) {
s->over_err++;
- set_uint32(s->scb + 22, s->over_err);
+ i82596_count_error(s, SCB_OVERRUN_ERRS);
}
if (error_type & RFD_STATUS_TRUNC) {
s->short_fr_error++;
- set_uint32(s->scb + 26, s->short_fr_error);
+ i82596_count_error(s, SCB_SHORT_ERRS);
}
}
}
@@ -439,8 +478,8 @@ static void i82596_tx_tfd_read(I82596State *s, hwaddr addr,
{
desc->status_bits = get_uint16(addr + 0);
desc->command = get_uint16(addr + 2);
- desc->link_addr = get_uint32(addr + 4);
- desc->tbd_addr = get_uint32(addr + 8);
+ desc->link_addr = get_addr(s, addr + 4);
+ desc->tbd_addr = get_addr(s, addr + 8);
desc->tcb_count = get_uint16(addr + 12);
address_space_read(&address_space_memory, addr + 14,
MEMTXATTRS_UNSPECIFIED, desc->dest_addr, 6);
@@ -452,8 +491,8 @@ static void i82596_tx_tfd_write(I82596State *s, hwaddr addr,
{
set_uint16(addr + 0, desc->status_bits);
set_uint16(addr + 2, desc->command);
- set_uint32(addr + 4, desc->link_addr);
- set_uint32(addr + 8, desc->tbd_addr);
+ set_addr(s, addr + 4, desc->link_addr);
+ set_addr(s, addr + 8, desc->tbd_addr);
set_uint16(addr + 12, desc->tcb_count);
address_space_write(&address_space_memory, addr + 14,
MEMTXATTRS_UNSPECIFIED, desc->dest_addr, 6);
@@ -464,8 +503,8 @@ static void i82596_tbd_read(I82596State *s, hwaddr addr,
struct i82596_tx_buffer_desc *tbd)
{
tbd->size = get_uint16(addr + 0);
- tbd->link = get_uint32(addr + 4);
- tbd->buffer = get_uint32(addr + 8);
+ tbd->link = get_addr(s, addr + 4);
+ tbd->buffer = get_addr(s, addr + 8);
}
static void i82596_rx_rfd_read(I82596State *s, hwaddr addr,
@@ -473,8 +512,8 @@ static void i82596_rx_rfd_read(I82596State *s, hwaddr addr,
{
desc->status_bits = get_uint16(addr + 0x0);
desc->command = get_uint16(addr + 0x2);
- desc->link = get_uint32(addr + 0x4);
- desc->rbd_addr = get_uint32(addr + 0x8);
+ desc->link = get_addr(s, addr + 0x4);
+ desc->rbd_addr = get_addr(s, addr + 0x8);
desc->actual_count = get_uint16(addr + 0xC);
desc->size = get_uint16(addr + 0xE);
@@ -494,8 +533,8 @@ static void i82596_rx_desc_write(I82596State *s, hwaddr addr,
if (write_full) {
set_uint16(addr + 0x2, desc->command);
- set_uint32(addr + 0x4, desc->link);
- set_uint32(addr + 0x8, desc->rbd_addr);
+ set_addr(s, addr + 0x4, desc->link);
+ set_addr(s, addr + 0x8, desc->rbd_addr);
set_uint16(addr + 0xE, desc->size);
address_space_write(&address_space_memory, addr + 0x10,
@@ -510,8 +549,8 @@ static void i82596_rbd_read(I82596State *s, hwaddr addr,
struct i82596_rx_buffer_desc *rbd)
{
rbd->actual_count = get_uint16(addr + 0x0);
- rbd->next_rbd_addr = get_uint32(addr + 0x4);
- rbd->buffer_addr = get_uint32(addr + 0x8);
+ rbd->next_rbd_addr = get_addr(s, addr + 0x4);
+ rbd->buffer_addr = get_addr(s, addr + 0x8);
rbd->size = get_uint16(addr + 0xC);
}
@@ -519,8 +558,8 @@ static void i82596_rbd_write(I82596State *s, hwaddr addr,
struct i82596_rx_buffer_desc *rbd)
{
set_uint16(addr + 0x0, rbd->actual_count);
- set_uint32(addr + 0x4, rbd->next_rbd_addr);
- set_uint32(addr + 0x8, rbd->buffer_addr);
+ set_addr(s, addr + 0x4, rbd->next_rbd_addr);
+ set_addr(s, addr + 0x8, rbd->buffer_addr);
set_uint16(addr + 0xC, rbd->size);
}
@@ -1008,7 +1047,7 @@ static ssize_t i82596_receive_packet(I82596State *s, const uint8_t *buf,
}
- rfd_addr = get_uint32(s->scb + 8);
+ rfd_addr = s->rfd_p;
if (rfd_addr == 0 || rfd_addr == I596_NULL) {
i82596_update_rx_state(s, RX_NO_RESOURCES);
@@ -1383,23 +1422,19 @@ static void i82596_update_statistics(I82596State *s, bool is_tx,
s->tx_collisions += collision_count;
s->collision_events++;
s->total_collisions += collision_count;
- set_uint32(s->scb + 32, s->tx_collisions);
}
if (error_flags) {
i82596_record_error(s, error_flags, true);
}
if (!(error_flags & (TX_ABORTED_ERRORS | TX_CARRIER_ERRORS))) {
s->tx_good_frames++;
- set_uint32(s->scb + 36, s->tx_good_frames);
}
} else {
s->total_frames++;
- set_uint32(s->scb + 40, s->total_frames);
if (error_flags) {
i82596_record_error(s, error_flags, false);
} else {
s->total_good_frames++;
- set_uint32(s->scb + 44, s->total_good_frames);
}
}
}
@@ -1557,7 +1592,7 @@ static void i82596_command_dump(I82596State *s, uint32_t cmd_addr)
uint16_t cmd = get_uint16(cmd_addr + 2);
uint16_t status;
- dump_addr = get_uint32(cmd_addr + 8);
+ dump_addr = get_addr(s, cmd_addr + 8);
i82596_init_dump_area(s, dump_buffer);
address_space_write(&address_space_memory, dump_addr,
@@ -1648,19 +1683,8 @@ static void i82596_update_cu_status(I82596State *s, uint16_t cmd_status,
static void update_scb_status(I82596State *s)
{
s->scb_status = (s->scb_status & 0xf000)
- | (s->cu_status << 8) | (s->rx_status << 4) | (s->lnkst >> 8);
+ | (s->cu_status << 8) | (s->rx_status << 4);
set_uint16(s->scb, s->scb_status);
-
- set_uint32(s->scb + 28, s->tx_aborted_errors);
- set_uint32(s->scb + 32, s->tx_collisions);
- set_uint32(s->scb + 36, s->tx_good_frames);
-
- set_uint32(s->scb + 16, s->crc_err);
- set_uint32(s->scb + 18, s->align_err);
- set_uint32(s->scb + 20, s->resource_err);
- set_uint32(s->scb + 22, s->over_err);
- set_uint32(s->scb + 24, s->rcvdt_err);
- set_uint32(s->scb + 26, s->short_fr_error);
}
static void command_loop(I82596State *s)
@@ -1669,11 +1693,12 @@ static void command_loop(I82596State *s)
s->cmd_p != 0) {
uint16_t status = get_uint16(s->cmd_p);
if (status & (STAT_C | STAT_B)) {
- uint32_t next = get_uint32(s->cmd_p + 4);
+ uint32_t next = get_addr(s, s->cmd_p + 4);
if (next == 0 || next == s->cmd_p) {
s->cmd_p = I596_NULL;
s->cu_status = CU_IDLE;
s->scb_status |= SCB_STATUS_CNA;
+ s->send_irq = 1;
break;
}
s->cmd_p = i82596_translate_address(s, next, false);
@@ -1681,7 +1706,7 @@ static void command_loop(I82596State *s)
}
set_uint16(s->cmd_p, STAT_B);
uint16_t cmd = get_uint16(s->cmd_p + 2);
- uint32_t next_addr = get_uint32(s->cmd_p + 4);
+ uint32_t next_addr = get_addr(s, s->cmd_p + 4);
next_addr = (next_addr == 0) ? I596_NULL :
i82596_translate_address(s, next_addr, false);
switch (cmd & CMD_MASK) {
@@ -1784,7 +1809,7 @@ static void examine_scb(I82596State *s)
break;
case SCB_CUC_START: {
- uint32_t cmd_ptr = get_uint32(s->scb + 4);
+ uint32_t cmd_ptr = get_addr(s, s->scb + 4);
s->cmd_p = i82596_translate_address(s, cmd_ptr, false);
s->cu_status = CU_ACTIVE;
break;
@@ -1823,7 +1848,7 @@ static void examine_scb(I82596State *s)
break;
case SCB_RUC_START: {
- uint32_t rfd_log = get_uint32(s->scb + 8);
+ uint32_t rfd_log = get_addr(s, s->scb + 8);
hwaddr rfd = i82596_translate_address(s, rfd_log, false);
if (rfd == 0 || rfd == I596_NULL) {
@@ -1862,12 +1887,11 @@ static void examine_scb(I82596State *s)
if (found) {
s->current_rx_desc = first_usable_rfd;
s->last_good_rfa = first_usable_rfd_log;
+ s->rbd_p = i82596_translate_address(s, test_rfd.rbd_addr, false);
+ s->rx_take_el = false;
+ s->rfd_p = first_usable_rfd;
i82596_update_rx_state(s, RX_READY);
- if (first_usable_rfd != rfd) {
- set_uint32(s->scb + 8, first_usable_rfd_log);
- }
-
if (s->queue_count > 0) {
trace_i82596_flush_queue(s->queue_count);
i82596_flush_packet_queue(s);
@@ -1909,7 +1933,7 @@ static void examine_scb(I82596State *s)
}
if (s->cu_status == CU_ACTIVE) {
if (s->cmd_p == I596_NULL) {
- s->cmd_p = get_uint32(s->scb + 4);
+ s->cmd_p = get_addr(s, s->scb + 4);
}
update_scb_status(s);
command_loop(s);
diff --git a/hw/net/i82596.h b/hw/net/i82596.h
index 67b18f957a..ec0b6a75ba 100644
--- a/hw/net/i82596.h
+++ b/hw/net/i82596.h
@@ -75,6 +75,9 @@ struct I82596State_st {
hwaddr current_tx_desc;
hwaddr current_rx_desc;
uint32_t last_good_rfa;
+ uint32_t rbd_p; /* next free RBD, loaded from the first RFD at RU start */
+ bool rx_take_el; /* hold timed out: fill the EL RBD like the chip does */
+ uint32_t rfd_p; /* next RFD, loaded from the SCB at RU start */
uint8_t packet_queue[PACKET_QUEUE_SIZE][PKT_BUF_SZ];
size_t packet_queue_len[PACKET_QUEUE_SIZE];
int queue_head;
--
2.54.0
next prev parent reply other threads:[~2026-11-05 22:32 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-05 22:31 [PULL v2 0/8] Hppa 715 cpu nic patches Helge Deller
2026-11-05 22:31 ` [PULL v2 1/8] target/hppa: Move emulated power button into CPU I/O region Helge Deller
2026-11-05 22:31 ` [PULL v2 2/8] target/hppa: Add special blr instruction for HP-UX 9.05 Helge Deller
2026-11-05 22:31 ` [PULL v2 3/8] lasi_i82596: Decode the PORT command from bits 3:0, not 7:0 Helge Deller
2026-11-05 22:31 ` Helge Deller [this message]
2026-11-05 22:31 ` [PULL v2 5/8] i82596: Initialize variables at chip reset Helge Deller
2026-11-05 22:31 ` [PULL v2 6/8] i82596: Drop crc calculation Helge Deller
2026-11-05 22:31 ` [PULL v2 7/8] i82596: Fix source address inserting Helge Deller
2026-11-05 22:31 ` [PULL v2 8/8] i82596: Various send- and transmit fixes for 715 Helge Deller
2026-11-06 16:46 ` [PULL v2 0/8] Hppa 715 cpu nic patches Richard Henderson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261105223122.8729-5-deller@kernel.org \
--to=deller@kernel.org \
--cc=deller@gmx.de \
--cc=keith@techtravels.org \
--cc=qemu-devel@nongnu.org \
--cc=richard.henderson@linaro.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.