LASI i82596 network driver fixes
As part of the Google Summer of Code 2025 program "Implementing LASI Network
Card and NCR 710 SCSI Controller Device Models" Soumyajyotii Ssarkar fixed
various bugs and enhanced the existing Qemu i82596 network card implementation.
Specifically he added or fixed the following functionality:
- Monitor Mode
- Promiscuous Mode
- Support for linear mode, segmented mode, and flexible memory models
- RX Timer
- Bus Throttle Timers
- Support for Little Endian mode
- Accurate CU and RU transition State
- HP-UX Specific Behavior Support
- Support for Loopback mode
- Self test
- Statistical counters
- VMstate descriptors
- Polling mechanism
- Transmit and Receive functions
-----BEGIN PGP SIGNATURE-----
iHUEABYKAB0WIQS86RI+GtKfB8BJu973ErUQojoPXwUCaQoaFAAKCRD3ErUQojoP
X/JLAP4mXjeN9G2F8xXEnCKDPoGFc16eQ/VjZJgh650KEHAO+gD/ZzSEeeoHGpp+
Kg0/FrKY4u1TpZCq9RYKWjoDTjrzSAc=
=26cF
-----END PGP SIGNATURE-----
Merge tag 'i82596-fixes-pull-request' of https://github.com/hdeller/qemu-hppa into staging
LASI i82596 network driver fixes
As part of the Google Summer of Code 2025 program "Implementing LASI Network
Card and NCR 710 SCSI Controller Device Models" Soumyajyotii Ssarkar fixed
various bugs and enhanced the existing Qemu i82596 network card implementation.
Specifically he added or fixed the following functionality:
- Monitor Mode
- Promiscuous Mode
- Support for linear mode, segmented mode, and flexible memory models
- RX Timer
- Bus Throttle Timers
- Support for Little Endian mode
- Accurate CU and RU transition State
- HP-UX Specific Behavior Support
- Support for Loopback mode
- Self test
- Statistical counters
- VMstate descriptors
- Polling mechanism
- Transmit and Receive functions
# -----BEGIN PGP SIGNATURE-----
#
# iHUEABYKAB0WIQS86RI+GtKfB8BJu973ErUQojoPXwUCaQoaFAAKCRD3ErUQojoP
# X/JLAP4mXjeN9G2F8xXEnCKDPoGFc16eQ/VjZJgh650KEHAO+gD/ZzSEeeoHGpp+
# Kg0/FrKY4u1TpZCq9RYKWjoDTjrzSAc=
# =26cF
# -----END PGP SIGNATURE-----
# gpg: Signature made Tue 04 Nov 2025 04:21:56 PM CET
# gpg: using EDDSA key BCE9123E1AD29F07C049BBDEF712B510A23A0F5F
# gpg: Good signature from "Helge Deller <deller@gmx.de>" [unknown]
# gpg: aka "Helge Deller <deller@kernel.org>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg: There is no indication that the signature belongs to the owner.
# Primary key fingerprint: 4544 8228 2CD9 10DB EF3D 25F8 3E5F 3D04 A7A2 4603
# Subkey fingerprint: BCE9 123E 1AD2 9F07 C049 BBDE F712 B510 A23A 0F5F
* tag 'i82596-fixes-pull-request' of https://github.com/hdeller/qemu-hppa:
i82596: Implement enhanced TX/RX with packet queuing and filtering
i82596: Added core infrastructure and helper functions
hw/hppa: Enable LASI i82596 network on 715 machine
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
f66930da44
7 changed files with 2015 additions and 531 deletions
|
|
@ -21,14 +21,6 @@
|
|||
#define DINO_SCSI_HPA 0xfff8c000
|
||||
#define LASI_HPA_715 0xf0100000
|
||||
#define LASI_HPA 0xffd00000
|
||||
#define LASI_UART_HPA 0xffd05000
|
||||
#define LASI_SCSI_HPA 0xffd06000
|
||||
#define LASI_LAN_HPA 0xffd07000
|
||||
#define LASI_RTC_HPA 0xffd09000
|
||||
#define LASI_LPT_HPA 0xffd02000
|
||||
#define LASI_AUDIO_HPA 0xffd04000
|
||||
#define LASI_PS2KBD_HPA 0xffd08000
|
||||
#define LASI_PS2MOU_HPA 0xffd08100
|
||||
#define LASI_GFX_HPA 0xf8000000
|
||||
#define ARTIST_FB_ADDR 0xf9000000
|
||||
#define CPU_HPA 0xfffb0000
|
||||
|
|
@ -44,6 +36,8 @@
|
|||
|
||||
#define SCSI_HPA 0xf1040000 /* emulated SCSI, needs to be in f region */
|
||||
|
||||
#define HPA_DISABLED_DEVICE 1 /* add to HPA to disable */
|
||||
|
||||
/* offsets to DINO HPA: */
|
||||
#define DINO_PCI_ADDR 0x064
|
||||
#define DINO_CONFIG_DATA 0x068
|
||||
|
|
|
|||
|
|
@ -50,8 +50,6 @@ struct HppaMachineState {
|
|||
#define HPA_POWER_BUTTON (FIRMWARE_END - 0x10)
|
||||
static hwaddr soft_power_reg;
|
||||
|
||||
#define enable_lasi_lan() 0
|
||||
|
||||
static DeviceState *lasi_dev;
|
||||
|
||||
static void hppa_powerdown_req(Notifier *n, void *opaque)
|
||||
|
|
@ -376,13 +374,6 @@ static void machine_HP_common_init_tail(MachineState *machine, PCIBus *pci_bus,
|
|||
}
|
||||
}
|
||||
|
||||
/* Network setup. */
|
||||
if (lasi_dev) {
|
||||
lasi_82596_init(addr_space, translate(NULL, LASI_LAN_HPA),
|
||||
qdev_get_gpio_in(lasi_dev, LASI_IRQ_LAN_HPA),
|
||||
enable_lasi_lan());
|
||||
}
|
||||
|
||||
if (pci_bus) {
|
||||
pci_init_nic_devices(pci_bus, mc->default_nic);
|
||||
|
||||
|
|
@ -595,6 +586,17 @@ static void machine_HP_715_init(MachineState *machine)
|
|||
lasi_ncr710_handle_legacy_cmdline(dev);
|
||||
}
|
||||
|
||||
/* LASI i82596 network */
|
||||
dev = qemu_create_nic_device(TYPE_LASI_82596, true, "lasi");
|
||||
if (dev) {
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
|
||||
qdev_get_gpio_in(lasi_dev, LASI_IRQ_LAN_HPA));
|
||||
memory_region_add_subregion(addr_space,
|
||||
translate(NULL, LASI_HPA_715 + LASI_LAN),
|
||||
sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0));
|
||||
}
|
||||
|
||||
/* Add NICs, graphics & load firmware */
|
||||
machine_HP_common_init_tail(machine, NULL, translate);
|
||||
}
|
||||
|
|
@ -638,7 +640,7 @@ static void machine_HP_B160L_init(MachineState *machine)
|
|||
assert(isa_bus);
|
||||
|
||||
/* Serial ports: Lasi and Dino use a 7.272727 MHz clock. */
|
||||
serial_mm_init(addr_space, translate(NULL, LASI_UART_HPA + 0x800), 0,
|
||||
serial_mm_init(addr_space, translate(NULL, LASI_HPA + LASI_UART + 0x800), 0,
|
||||
qdev_get_gpio_in(lasi_dev, LASI_IRQ_UART_HPA), 7272727 / 16,
|
||||
serial_hd(0), DEVICE_BIG_ENDIAN);
|
||||
|
||||
|
|
@ -647,7 +649,8 @@ static void machine_HP_B160L_init(MachineState *machine)
|
|||
serial_hd(1), DEVICE_BIG_ENDIAN);
|
||||
|
||||
/* Parallel port */
|
||||
parallel_mm_init(addr_space, translate(NULL, LASI_LPT_HPA + 0x800), 0,
|
||||
parallel_mm_init(addr_space,
|
||||
translate(NULL, LASI_HPA + LASI_LPT + 0x800), 0,
|
||||
qdev_get_gpio_in(lasi_dev, LASI_IRQ_LPT_HPA),
|
||||
parallel_hds[0]);
|
||||
|
||||
|
|
@ -657,11 +660,11 @@ static void machine_HP_B160L_init(MachineState *machine)
|
|||
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0,
|
||||
qdev_get_gpio_in(lasi_dev, LASI_IRQ_PS2KBD_HPA));
|
||||
memory_region_add_subregion(addr_space,
|
||||
translate(NULL, LASI_PS2KBD_HPA),
|
||||
translate(NULL, LASI_HPA + LASI_PS2),
|
||||
sysbus_mmio_get_region(SYS_BUS_DEVICE(dev),
|
||||
0));
|
||||
memory_region_add_subregion(addr_space,
|
||||
translate(NULL, LASI_PS2KBD_HPA + 0x100),
|
||||
translate(NULL, LASI_HPA + LASI_PS2 + 0x100),
|
||||
sysbus_mmio_get_region(SYS_BUS_DEVICE(dev),
|
||||
1));
|
||||
|
||||
|
|
@ -832,7 +835,7 @@ static void HP_715_machine_init_class_init(ObjectClass *oc, const void *data)
|
|||
/* can only support up to max. 8 CPUs due inventory major numbers */
|
||||
mc->max_cpus = MIN_CONST(HPPA_MAX_CPUS, 8);
|
||||
mc->default_ram_size = 256 * MiB;
|
||||
mc->default_nic = NULL;
|
||||
mc->default_nic = TYPE_LASI_82596;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
2371
hw/net/i82596.c
2371
hw/net/i82596.c
File diff suppressed because it is too large
Load diff
|
|
@ -6,11 +6,15 @@
|
|||
#include "system/memory.h"
|
||||
#include "system/address-spaces.h"
|
||||
|
||||
#define PORT_RESET 0x00 /* reset 82596 */
|
||||
#define PORT_SELFTEST 0x01 /* selftest */
|
||||
#define PORT_ALTSCP 0x02 /* alternate SCB address */
|
||||
#define PORT_ALTDUMP 0x03 /* Alternate DUMP address */
|
||||
#define PORT_CA 0x10 /* QEMU-internal CA signal */
|
||||
#define PACKET_QUEUE_SIZE 64
|
||||
#define RX_RING_SIZE 16
|
||||
#define PKT_BUF_SZ 1536
|
||||
|
||||
#define PORT_RESET 0x00
|
||||
#define PORT_SELFTEST 0x01
|
||||
#define PORT_ALTSCP 0x02
|
||||
#define PORT_ALTDUMP 0x03
|
||||
#define PORT_CA 0x10
|
||||
|
||||
typedef struct I82596State_st I82596State;
|
||||
|
||||
|
|
@ -21,35 +25,75 @@ struct I82596State_st {
|
|||
NICState *nic;
|
||||
NICConf conf;
|
||||
QEMUTimer *flush_queue_timer;
|
||||
uint8_t mode;
|
||||
|
||||
hwaddr scp; /* pointer to SCP */
|
||||
QEMUTimer *throttle_timer;
|
||||
uint16_t t_on;
|
||||
uint16_t t_off;
|
||||
bool throttle_state;
|
||||
|
||||
hwaddr scp;
|
||||
uint32_t iscp;
|
||||
uint8_t sysbus;
|
||||
uint32_t scb; /* SCB */
|
||||
uint32_t scb;
|
||||
uint32_t scb_base;
|
||||
uint16_t scb_status;
|
||||
uint8_t cu_status, rx_status;
|
||||
uint16_t lnkst;
|
||||
uint32_t last_tx_len;
|
||||
uint32_t collision_events;
|
||||
uint32_t total_collisions;
|
||||
|
||||
uint32_t cmd_p; /* addr of current command */
|
||||
uint32_t tx_retry_addr;
|
||||
int tx_retry_count;
|
||||
uint32_t tx_good_frames;
|
||||
uint32_t tx_collisions;
|
||||
uint32_t tx_aborted_errors;
|
||||
|
||||
uint32_t cmd_p;
|
||||
int ca;
|
||||
int ca_active;
|
||||
int send_irq;
|
||||
|
||||
/* Hash register (multicast mask array, multiple individual addresses). */
|
||||
uint8_t mult[8];
|
||||
uint8_t config[14]; /* config bytes from CONFIGURE command */
|
||||
uint8_t config[14];
|
||||
|
||||
uint8_t tx_buffer[0x4000];
|
||||
uint32_t crc_err;
|
||||
uint32_t align_err;
|
||||
uint32_t resource_err;
|
||||
uint32_t over_err;
|
||||
uint32_t rcvdt_err;
|
||||
uint32_t short_fr_error;
|
||||
uint32_t total_frames;
|
||||
uint32_t total_good_frames;
|
||||
|
||||
uint8_t tx_buffer[PKT_BUF_SZ];
|
||||
uint8_t rx_buffer[PKT_BUF_SZ];
|
||||
uint16_t tx_frame_len;
|
||||
uint16_t rx_frame_len;
|
||||
|
||||
hwaddr current_tx_desc;
|
||||
hwaddr current_rx_desc;
|
||||
uint32_t last_good_rfa;
|
||||
uint8_t packet_queue[PACKET_QUEUE_SIZE][PKT_BUF_SZ];
|
||||
size_t packet_queue_len[PACKET_QUEUE_SIZE];
|
||||
int queue_head;
|
||||
int queue_tail;
|
||||
int queue_count;
|
||||
bool rnr_signaled;
|
||||
bool flushing_queue;
|
||||
};
|
||||
|
||||
void i82596_h_reset(void *opaque);
|
||||
void i82596_ioport_writew(void *opaque, uint32_t addr, uint32_t val);
|
||||
uint32_t i82596_ioport_readw(void *opaque, uint32_t addr);
|
||||
void i82596_ioport_writel(void *opaque, uint32_t addr, uint32_t val);
|
||||
uint32_t i82596_ioport_readl(void *opaque, uint32_t addr);
|
||||
uint32_t i82596_bcr_readw(I82596State *s, uint32_t rap);
|
||||
ssize_t i82596_receive(NetClientState *nc, const uint8_t *buf, size_t size_);
|
||||
ssize_t i82596_receive_iov(NetClientState *nc, const struct iovec *iov,
|
||||
int iovcnt);
|
||||
bool i82596_can_receive(NetClientState *nc);
|
||||
void i82596_set_link_status(NetClientState *nc);
|
||||
void i82596_common_init(DeviceState *dev, I82596State *s, NetClientInfo *info);
|
||||
void i82596_poll(NetClientState *nc, bool enable);
|
||||
void i82596_common_init(DeviceState *dev, I82596State *s,
|
||||
NetClientInfo *info);
|
||||
extern const VMStateDescription vmstate_i82596;
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -86,6 +86,10 @@ static const MemoryRegionOps lasi_82596_mem_ops = {
|
|||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
.impl = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
},
|
||||
};
|
||||
|
||||
static NetClientInfo net_lasi_82596_info = {
|
||||
|
|
@ -93,6 +97,8 @@ static NetClientInfo net_lasi_82596_info = {
|
|||
.size = sizeof(NICState),
|
||||
.can_receive = i82596_can_receive,
|
||||
.receive = i82596_receive,
|
||||
.receive_iov = i82596_receive_iov,
|
||||
.poll = i82596_poll,
|
||||
.link_status_changed = i82596_set_link_status,
|
||||
};
|
||||
|
||||
|
|
@ -115,32 +121,12 @@ static void lasi_82596_realize(DeviceState *dev, Error **errp)
|
|||
memory_region_init_io(&s->mmio, OBJECT(d), &lasi_82596_mem_ops, d,
|
||||
"lasi_82596-mmio", PA_GET_MACADDR + 4);
|
||||
|
||||
sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
|
||||
|
||||
i82596_common_init(dev, s, &net_lasi_82596_info);
|
||||
}
|
||||
|
||||
SysBusI82596State *lasi_82596_init(MemoryRegion *addr_space, hwaddr hpa,
|
||||
qemu_irq lan_irq, gboolean match_default)
|
||||
{
|
||||
DeviceState *dev;
|
||||
SysBusI82596State *s;
|
||||
static const MACAddr HP_MAC = {
|
||||
.a = { 0x08, 0x00, 0x09, 0xef, 0x34, 0xf6 } };
|
||||
|
||||
dev = qemu_create_nic_device(TYPE_LASI_82596, match_default, "lasi");
|
||||
if (!dev) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s = SYSBUS_I82596(dev);
|
||||
s->state.irq = lan_irq;
|
||||
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
|
||||
s->state.conf.macaddr = HP_MAC; /* set HP MAC prefix */
|
||||
|
||||
/* LASI 82596 ports in main memory. */
|
||||
memory_region_add_subregion(addr_space, hpa, &s->state.mmio);
|
||||
return s;
|
||||
}
|
||||
|
||||
static void lasi_82596_reset(DeviceState *dev)
|
||||
{
|
||||
SysBusI82596State *d = SYSBUS_I82596(dev);
|
||||
|
|
@ -152,6 +138,10 @@ static void lasi_82596_instance_init(Object *obj)
|
|||
{
|
||||
SysBusI82596State *d = SYSBUS_I82596(obj);
|
||||
I82596State *s = &d->state;
|
||||
static const MACAddr HP_MAC = {
|
||||
.a = { 0x08, 0x00, 0x09, 0xef, 0x34, 0xf6 } };
|
||||
|
||||
s->conf.macaddr = HP_MAC;
|
||||
|
||||
device_add_bootindex_property(obj, &s->conf.bootindex,
|
||||
"bootindex", "/ethernet-phy@0",
|
||||
|
|
|
|||
|
|
@ -421,10 +421,27 @@ lasi_82596_mem_writew(uint64_t addr, uint32_t val) "addr=0x%"PRIx64" val=0x%04x"
|
|||
i82596_s_reset(void *s) "%p Reset chip"
|
||||
i82596_transmit(uint32_t size, uint32_t addr) "size %u from addr 0x%04x"
|
||||
i82596_receive_analysis(const char *s) "%s"
|
||||
i82596_receive_packet(size_t sz) "len=%zu"
|
||||
i82596_receive_queue_full(void) "Packet queue full, dropping packet"
|
||||
i82596_receive_suspended(void) "RX unit suspended, queueing packet"
|
||||
i82596_rx_state_change(uint8_t old_state, uint8_t new_state) "RX state changed from %d to %d"
|
||||
i82596_new_mac(const char *id_with_mac) "New MAC for: %s"
|
||||
i82596_set_multicast(uint16_t count) "Added %d multicast entries"
|
||||
i82596_channel_attention(void *s) "%p: Received CHANNEL ATTENTION"
|
||||
i82596_scb_command(uint8_t cuc, uint8_t ruc) "SCB command CUC=0x%02x RUC=0x%02x"
|
||||
i82596_dump(uint32_t addr) "Dump command to addr 0x%08x"
|
||||
i82596_flush_queue(int count) "Flushing %d packets from queue"
|
||||
i82596_tx_tfd(uint64_t addr, uint16_t status, uint16_t cmd, uint32_t link, uint32_t tbd) "TFD @0x%"PRIx64": status=0x%04x cmd=0x%04x link=0x%08x tbd=0x%08x"
|
||||
i82596_tx_tbd(uint64_t addr, uint16_t size, uint32_t buf) "TBD @0x%"PRIx64": size=%d buf=0x%08x"
|
||||
i82596_rx_rfd(uint64_t addr, uint16_t status, uint16_t cmd, uint32_t link, uint32_t rbd) "RFD @0x%"PRIx64": status=0x%04x cmd=0x%04x link=0x%08x rbd=0x%08x"
|
||||
i82596_rx_rbd(uint64_t addr, uint16_t count, uint32_t buf, uint16_t size) "RBD @0x%"PRIx64": count=%d buf=0x%08x size=%d"
|
||||
i82596_receive_packet(const uint8_t *buf, size_t size) "RX packet %p size %zu"
|
||||
i82596_rx_short_frame(size_t size) "RX: Frame too short (%zu bytes)"
|
||||
i82596_rx_rfd_update(uint32_t addr, uint32_t next_rfd) "RX: Updating RFD 0x%08x to point to 0x%08x"
|
||||
i82596_rx_out_of_rbds(void) "RX: Out of RBDs mid-frame"
|
||||
i82596_rx_incomplete(size_t copied, size_t total) "RX: Incomplete copy (%zu/%zu bytes)"
|
||||
i82596_rx_complete(uint32_t crc, uint32_t align, uint32_t resource) "RX: Complete (errors: CRC=%d align=%d res=%d)"
|
||||
i82596_receive_iov(size_t size, int iovcnt) "RX IOV: %zu bytes in %d vectors"
|
||||
i82596_ca_init(uint32_t scb, uint8_t mode, uint32_t base) "CA: Init - SCB=0x%08x mode=%d base=0x%08x"
|
||||
i82596_ioport_write(uint32_t addr, uint32_t val) "IO write addr=0x%08x val=0x%08x"
|
||||
|
||||
# imx_fec.c
|
||||
imx_phy_read_num(int phy, int configured) "read request from unconfigured phy %d (configured %d)"
|
||||
|
|
|
|||
|
|
@ -25,7 +25,4 @@ struct SysBusI82596State {
|
|||
int val_index:1;
|
||||
};
|
||||
|
||||
SysBusI82596State *lasi_82596_init(MemoryRegion *addr_space, hwaddr hpa,
|
||||
qemu_irq irq, gboolean match_default);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue