* [Qemu-devel] [PATCH] DM9000 network card driver
@ 2008-10-27 10:49 Daniel Silverstone
2008-11-10 10:31 ` Daniel Silverstone
0 siblings, 1 reply; 5+ messages in thread
From: Daniel Silverstone @ 2008-10-27 10:49 UTC (permalink / raw)
To: qemu-devel
[-- Attachment #1: Type: text/plain, Size: 625 bytes --]
Hi,
I think this fell through the cracks, so here it is again.
The Davicom DM9000 10/100 Ethernet controller.
This driver supplies an MMIO based DM9000 interface which can be
instantiated in the emulation's memory map to provide an ethernet
interface for ARM "local-bus" type systems.
Signed-off-by: Daniel Silverstone <dsilvers@simtec.co.uk>
Signed-off-by: Vincent Sanders <vince@simtec.co.uk>
I believe I covered all previously raised objections.
Regards,
Daniel.
--
Daniel Silverstone http://www.simtec.co.uk/
PGP mail accepted and encouraged. Key Id: 2BC8 4016 2068 7895
[-- Attachment #2: dm9000.patch --]
[-- Type: text/x-patch, Size: 22403 bytes --]
The Davicom DM9000 10/100 Ethernet controller.
This driver supplies an MMIO based DM9000 interface which can be
instantiated in the emulation's memory map to provide an ethernet
interface for ARM "local-bus" type systems.
Signed-off-by: Daniel Silverstone <dsilvers@simtec.co.uk>
Signed-off-by: Vincent Sanders <vince@simtec.co.uk>
Makefile.target | 2
hw/devices.h | 7
hw/dm9000.c | 631 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 639 insertions(+), 1 deletion(-)
=== modified file 'Makefile.target'
--- Makefile.target 2008-10-13 03:14:31 +0000
+++ Makefile.target 2008-10-13 14:59:29 +0000
@@ -599,7 +599,7 @@
ifeq ($(TARGET_BASE_ARCH), arm)
OBJS+= integratorcp.o versatilepb.o ps2.o smc91c111.o arm_pic.o arm_timer.o
OBJS+= arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o
-OBJS+= versatile_pci.o ptimer.o
+OBJS+= versatile_pci.o ptimer.o dm9000.o
OBJS+= realview_gic.o realview.o arm_sysctl.o mpcore.o
OBJS+= armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
OBJS+= pl061.o
=== modified file 'hw/devices.h'
--- hw/devices.h 2008-06-09 00:03:13 +0000
+++ hw/devices.h 2008-10-13 14:14:44 +0000
@@ -3,6 +3,13 @@
/* Devices that have nowhere better to go. */
+/* dm9000.c */
+#ifdef NEED_CPU_H
+/* This ifdef is present because target_phys_addr_t comes from cpu-defs.h */
+void dm9000_init(NICInfo *nd, target_phys_addr_t base_addr, uint32_t addr_offset,
+ uint32_t data_offset, qemu_irq irq);
+#endif
+
/* smc91c111.c */
void smc91c111_init(NICInfo *, uint32_t, qemu_irq);
=== added file 'hw/dm9000.c'
--- hw/dm9000.c 1970-01-01 00:00:00 +0000
+++ hw/dm9000.c 2008-10-13 15:05:45 +0000
@@ -0,0 +1,631 @@
+/* hw/dm9000.c
+ *
+ * DM9000 Ethernet interface
+ *
+ * Copyright 2006, 2008 Daniel Silverstone and Vincent Sanders
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; version 2 only.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <string.h>
+#include "qemu-common.h"
+#include "hw/irq.h"
+#include "net.h"
+
+/* Comment this out if you don't want register debug on stderr */
+/* #define DM9000_DEBUG */
+
+#ifdef DM9000_DEBUG
+#define DM9000_DBF(X...) do { fprintf(stderr, X); } while(0)
+#else
+#define DM9000_DBF(X...) do { if (0) fprintf(stderr, X); } while (0)
+#endif
+
+#define DM9000_REG_NCR 0x00
+#define DM9000_REG_NSR 0x01
+#define DM9000_REG_TCR 0x02
+#define DM9000_REG_TSR1 0x03
+#define DM9000_REG_TSR2 0x04
+#define DM9000_REG_RCR 0x05
+#define DM9000_REG_RSR 0x06
+#define DM9000_REG_ROCR 0x07
+#define DM9000_REG_BPTR 0x08
+#define DM9000_REG_FCTR 0x09
+#define DM9000_REG_FCR 0x0A
+#define DM9000_REG_EPCR 0x0B
+#define DM9000_REG_EPAR 0x0C
+#define DM9000_REG_EPDRL 0x0D
+#define DM9000_REG_EPDRH 0x0E
+#define DM9000_REG_WCR 0x0F
+#define DM9000_REG_PAR0 0x10
+#define DM9000_REG_PAR1 0x11
+#define DM9000_REG_PAR2 0x12
+#define DM9000_REG_PAR3 0x13
+#define DM9000_REG_PAR4 0x14
+#define DM9000_REG_PAR5 0x15
+#define DM9000_REG_MAR0 0x16
+#define DM9000_REG_MAR1 0x17
+#define DM9000_REG_MAR2 0x18
+#define DM9000_REG_MAR3 0x19
+#define DM9000_REG_MAR4 0x1A
+#define DM9000_REG_MAR5 0x1B
+#define DM9000_REG_MAR6 0x1C
+#define DM9000_REG_MAR7 0x1D
+#define DM9000_REG_GPCR 0x1E
+#define DM9000_REG_GPR 0x1F
+#define DM9000_REG_TRPAL 0x22
+#define DM9000_REG_TRPAH 0x23
+#define DM9000_REG_RWPAL 0x24
+#define DM9000_REG_RWPAH 0x25
+#define DM9000_REG_VIDL 0x28
+#define DM9000_REG_VIDH 0x29
+#define DM9000_REG_PIDL 0x2A
+#define DM9000_REG_PIDH 0x2B
+#define DM9000_REG_CHIPR 0x2C
+#define DM9000_REG_SMCR 0x2F
+#define DM9000_REG_MRCMDX 0xF0
+#define DM9000_REG_MRCMD 0xF2
+#define DM9000_REG_MRRL 0xF4
+#define DM9000_REG_MRRH 0xF5
+#define DM9000_REG_MWCMDX 0xF6
+#define DM9000_REG_MWCMD 0xF8
+#define DM9000_REG_MWRL 0xFA
+#define DM9000_REG_MWRH 0xFB
+#define DM9000_REG_TXPLL 0xFC
+#define DM9000_REG_TXPLH 0xFD
+#define DM9000_REG_ISR 0xFE
+#define DM9000_REG_IMR 0xFF
+
+#define DM9000_NCR_RESET 0x01
+#define DM9000_NSR_TX1END 0x04
+#define DM9000_NSR_TX2END 0x08
+#define DM9000_TCR_TXREQ 0x01
+
+#define DM9000_IMR_AUTOWRAP 0x80
+
+#define DM9000_MII_READ 0x0C
+#define DM9000_MII_WRITE 0x0A
+
+#define DM9000_MII_REG_BMCR 0x00
+#define DM9000_MII_REG_STATUS 0x01
+#define DM9000_MII_REG_PHYID1 0x02
+#define DM9000_MII_REG_PHYID2 0x03
+#define DM9000_MII_REG_ANAR 0x04
+#define DM9000_MII_REG_ANLPAR 0x05
+#define DM9000_MII_REG_ANER 0x06
+#define DM9000_MII_REG_DSCR 0x10
+#define DM9000_MII_REG_DSCSR 0x11
+#define DM9000_MII_REG_10BTCSR 0x12
+
+
+typedef struct {
+ target_phys_addr_t addr; /* address port */
+ target_phys_addr_t data; /* data port */
+ VLANClientState *vc;
+ qemu_irq irq;
+ uint8_t macaddr[6];
+ uint8_t multihash[8]; /* multicast hash table */
+ uint8_t address; /* The internal magial address */
+ uint8_t packet_buffer[16 * 1024];
+ uint16_t dm9k_mrr, dm9k_mwr; /* Read and write address registers */
+ uint16_t dm9k_txpl; /* TX packet length */
+ uint16_t dm9k_trpa, dm9k_rwpa; /* TX Read ptr address, RX write ptr address */
+ uint8_t dm9k_imr, dm9k_isr; /* Interrupt mask register and status register*/
+ uint8_t dm9k_ncr, dm9k_nsr; /* Network control register, network status register */
+ uint8_t dm9k_wcr; /* Wakeup control */
+ uint8_t dm9k_tcr; /* Transmission control register */
+ uint8_t packet_copy_buffer[3 * 1024]; /* packet copy buffer */
+ unsigned int packet_index:1; /* 0 == packet I, 1 == packet II */
+
+ /* Internal MII PHY state */
+ uint8_t dm9k_epcr; /* EEPROM/PHY control register */
+ uint8_t dm9k_epar; /* EEPROM/PHY address register */
+ uint16_t dm9k_epdr; /* EEPROM/PHY data register */
+ /* MII Regs */
+ uint16_t dm9k_mii_bmcr;
+ uint16_t dm9k_mii_anar;
+ uint16_t dm9k_mii_dscr;
+} dm9000_state;
+
+static void dm9000_raise_irq(dm9000_state *state)
+{
+ int level = ((state->dm9k_isr & state->dm9k_imr) & 0x03) != 0;
+ DM9000_DBF("DM9000: Set IRQ level %d\n", level);
+ qemu_set_irq(state->irq, level);
+}
+
+static void dm9000_soft_reset_mii(dm9000_state *state)
+{
+ state->dm9k_mii_bmcr = 0x3100; /* 100Mbps, AUTONEG, FULL DUPLEX */
+ state->dm9k_mii_anar = 0x01E1;
+ state->dm9k_mii_dscr = 0x0410;
+}
+
+static void dm9000_soft_reset(dm9000_state *state)
+{
+ DM9000_DBF("DM9000: Soft Reset\n");
+ state->dm9k_mrr = state->dm9k_mwr = state->dm9k_txpl = state->dm9k_trpa = 0x0000;
+ state->dm9k_rwpa = 0x0C04;
+ state->dm9k_imr = 0;
+ state->dm9k_isr = 0; /* 16 bit mode, no interrupts asserted */
+ state->dm9k_tcr = 0;
+ state->packet_index = 0;
+ memset(state->packet_buffer, 0, 16*1024);
+ memset(state->packet_copy_buffer, 0, 3*1024);
+ /* These registers have some bits "unaffected by software reset" */
+ /* Clear the reset bits */
+ state->dm9k_ncr &= 0xA0;
+ state->dm9k_nsr &= 0xD0;
+ /* Claim full duplex */
+ state->dm9k_ncr |= 1<<3;
+ /* Set link status to 1 */
+ state->dm9k_nsr |= 1<<6;
+ /* dm9k_wcr is unaffected or reserved, never reset */
+ /* MII control regs */
+ state->dm9k_epcr = 0x00;
+ state->dm9k_epar = 0x40;
+ /* reset the MII */
+ dm9000_soft_reset_mii(state);
+ dm9000_raise_irq(state); /* Clear any potentially pending IRQ */
+}
+
+static void dm9000_hard_reset(dm9000_state *state)
+{
+ state->dm9k_ncr = 0x00;
+ state->dm9k_nsr = 0x00;
+ state->dm9k_wcr = 0x00;
+ dm9000_soft_reset(state);
+}
+
+static void dm9000_do_transmit(dm9000_state *state)
+{
+ uint16_t idx, cnt, tptr;
+ idx = state->dm9k_trpa;
+ cnt = state->dm9k_txpl;
+ tptr = 0;
+ if( cnt > 3*1024 ) cnt = 3*1024; /* HARD CAP AT 3KiB */
+ DM9000_DBF("TX_Packet: %d bytes from %04x\n", cnt, idx);
+ while(cnt--) {
+ state->packet_copy_buffer[tptr++] = state->packet_buffer[idx++];
+ if( idx == 0x0C00 ) idx = 0;
+ }
+ /* DM9KNOTE: Assumes 16bit wiring */
+ idx = (idx+1) & ~1; /* Round up to nearest 16bit boundary */
+ if( idx == 0x0C00 ) idx = 0;
+ state->dm9k_trpa = idx;
+ /* We have the copy buffer, now we do the transmit */
+ qemu_send_packet(state->vc, state->packet_copy_buffer, state->dm9k_txpl);
+ /* Clear the "please xmit" bit */
+ state->dm9k_tcr &= ~DM9000_TCR_TXREQ;
+ /* Set the TXEND bit */
+ state->dm9k_nsr |= 1<<(2+state->packet_index);
+ DM9000_DBF("TX: NSR=%02x PI=%d\n", state->dm9k_nsr, state->packet_index);
+ /* Claim a TX complete IRQ */
+ state->dm9k_isr |= 0x02; /* Packet transmitted latch */
+ /* And flip the next-packet bit */
+ state->packet_index = !state->packet_index;
+ dm9000_raise_irq(state);
+}
+
+static void dm9000_mii_read(dm9000_state *state)
+{
+ int mii_reg = (state->dm9k_epar) & 0x3f;
+ uint16_t ret = 0;
+ switch(mii_reg) {
+ case DM9000_MII_REG_BMCR:
+ ret = state->dm9k_mii_bmcr;
+ break;
+ case DM9000_MII_REG_STATUS:
+ ret = 0x782D; /* No 100/T4, Can 100/FD, Can 100/HD, Can 10/FD, Can 10/HD,
+ * No Preamble suppression, Autoneg complete, No remote fault,
+ * Can autoneg, link up, no jabber, extended capability */
+ break;
+ case DM9000_MII_REG_PHYID1:
+ ret = 0x0181;
+ break;
+ case DM9000_MII_REG_PHYID2:
+ ret = 0xB8C0;
+ break;
+ case DM9000_MII_REG_ANAR:
+ ret = state->dm9k_mii_anar;
+ break;
+ case DM9000_MII_REG_ANLPAR:
+ ret = 0x0400;
+ break;
+ case DM9000_MII_REG_ANER:
+ ret = 0x0001;
+ break;
+ case DM9000_MII_REG_DSCR:
+ ret = state->dm9k_mii_dscr;
+ break;
+ case DM9000_MII_REG_DSCSR:
+ ret = 0xF008;
+ break;
+ case DM9000_MII_REG_10BTCSR:
+ ret = 0x7800;
+ }
+ state->dm9k_epdr = ret;
+ DM9000_DBF("DM9000:MIIPHY: Read of MII reg %d gives %04x\n", mii_reg, state->dm9k_epdr);
+}
+
+static void dm9000_mii_write(dm9000_state *state)
+{
+ int mii_reg = (state->dm9k_epar) & 0x3f;
+ DM9000_DBF("DM9000:MIIPHY: Write of MII reg %d value %04x\n", mii_reg, state->dm9k_epdr);
+ switch(mii_reg) {
+ case DM9000_MII_REG_BMCR:
+ state->dm9k_mii_bmcr = (state->dm9k_epdr &~0x8000);
+ if( state->dm9k_epdr & 0x8000 ) dm9000_soft_reset_mii(state);
+ break;
+ case DM9000_MII_REG_ANAR:
+ state->dm9k_mii_anar = state->dm9k_epdr;
+ break;
+ case DM9000_MII_REG_DSCR:
+ state->dm9k_mii_dscr = state->dm9k_epdr & ~0x0008;
+ break;
+ }
+}
+
+static void dm9000_write(void *opaque, target_phys_addr_t address,
+ uint32_t value)
+{
+ dm9000_state *state = (dm9000_state *)opaque;
+#ifdef DM9000_DEBUG
+ int suppress_debug = 0;
+#endif
+
+ if (address == state->addr) {
+ if( (value != DM9000_REG_MRCMD) &&
+ (value != DM9000_REG_MWCMD) )
+ DM9000_DBF("DM9000: Address set to 0x%02x\n", value);
+ state->address = value;
+ return;
+ }
+
+ if (address != state->data) {
+ DM9000_DBF("DM9000: Write to location which is neither data nor address port: " TARGET_FMT_plx "\n", address);
+ }
+
+ switch(state->address) {
+ case DM9000_REG_NCR:
+ state->dm9k_ncr = value & 0xDF;
+ if (state->dm9k_ncr & DM9000_NCR_RESET)
+ dm9000_soft_reset(state);
+ break;
+ case DM9000_REG_NSR:
+ state->dm9k_nsr &= ~(value & 0x2C);
+ break;
+ case DM9000_REG_TCR:
+ state->dm9k_tcr = value & 0xFF;
+ if( value & DM9000_TCR_TXREQ ) dm9000_do_transmit(state);
+ break;
+ case DM9000_REG_EPCR:
+ state->dm9k_epcr = value & 0xFF;
+ if( value & DM9000_MII_READ )
+ dm9000_mii_read(state);
+ else if( value & DM9000_MII_WRITE )
+ dm9000_mii_write(state);
+ break;
+ case DM9000_REG_EPAR:
+ state->dm9k_epar = value & 0xFF;
+ break;
+ case DM9000_REG_EPDRL:
+ state->dm9k_epdr &= 0xFF00;
+ state->dm9k_epdr |= value & 0xFF;
+ break;
+ case DM9000_REG_EPDRH:
+ state->dm9k_epdr &= 0xFF;
+ state->dm9k_epdr |= (value & 0xFF) << 8;
+ break;
+ case DM9000_REG_PAR0:
+ case DM9000_REG_PAR1:
+ case DM9000_REG_PAR2:
+ case DM9000_REG_PAR3:
+ case DM9000_REG_PAR4:
+ case DM9000_REG_PAR5:
+ state->macaddr[state->address - DM9000_REG_PAR0] = value & 0xFF;
+ break;
+ case DM9000_REG_MAR0:
+ case DM9000_REG_MAR1:
+ case DM9000_REG_MAR2:
+ case DM9000_REG_MAR3:
+ case DM9000_REG_MAR4:
+ case DM9000_REG_MAR5:
+ case DM9000_REG_MAR6:
+ case DM9000_REG_MAR7:
+ /* multicast hash setup */
+ state->multihash[state->address - DM9000_REG_MAR0] = value & 0xFF;
+ break;
+ case DM9000_REG_MRRL:
+ state->dm9k_mrr &= 0xFF00;
+ state->dm9k_mrr |= value & 0xFF;
+ break;
+ case DM9000_REG_MRRH:
+ state->dm9k_mrr &= 0xFF;
+ state->dm9k_mrr |= (value & 0xFF) << 8;
+ break;
+ case DM9000_REG_MWCMDX:
+ case DM9000_REG_MWCMD:
+ /* DM9KNOTE: This assumes a 16bit wide wiring */
+ state->packet_buffer[state->dm9k_mwr] = value & 0xFF;
+ state->packet_buffer[state->dm9k_mwr+1] = (value >> 8) & 0xFF;
+ if( state->address == DM9000_REG_MWCMD ) {
+ state->dm9k_mwr += 2;
+ if( state->dm9k_imr & DM9000_IMR_AUTOWRAP )
+ if( state->dm9k_mwr >= 0x0C00 )
+ state->dm9k_mwr -= 0x0C00;
+ }
+#ifdef DM9000_DEBUG
+ suppress_debug = 1;
+#endif
+ break;
+ case DM9000_REG_MWRL:
+ state->dm9k_mwr &= 0xFF00;
+ state->dm9k_mwr |= value & 0xFF;
+ break;
+ case DM9000_REG_MWRH:
+ state->dm9k_mwr &= 0xFF;
+ state->dm9k_mwr |= (value & 0xFF) << 8;
+ break;
+ case DM9000_REG_TXPLL:
+ state->dm9k_txpl &= 0xFF00;
+ state->dm9k_txpl |= value & 0xFF;
+ break;
+ case DM9000_REG_TXPLH:
+ state->dm9k_txpl &= 0xFF;
+ state->dm9k_txpl |= (value & 0xFF) << 8;
+ break;
+ case DM9000_REG_ISR:
+ state->dm9k_isr &= ~(value & 0x0F);
+ dm9000_raise_irq(state);
+ break;
+ case DM9000_REG_IMR:
+ if( !(state->dm9k_imr & DM9000_IMR_AUTOWRAP) &&
+ (value & DM9000_IMR_AUTOWRAP) )
+ state->dm9k_mrr = 0x0C00 | (state->dm9k_mrr & 0xFF);
+ state->dm9k_imr = value & 0xFF;
+ dm9000_raise_irq(state);
+ break;
+ }
+#ifdef DM9000_DEBUG
+ if(!suppress_debug) DM9000_DBF("DM9000: Write value %04x\n", value);
+#endif
+}
+
+static uint32_t dm9000_read(void *opaque, target_phys_addr_t address)
+{
+ dm9000_state *state = (dm9000_state *)opaque;
+ uint32_t ret = 0;
+#ifdef DM9000_DEBUG
+ int suppress_debug = 0;
+#endif
+
+ if (address == state->addr)
+ return state->address;
+
+ if (address != state->data) {
+ DM9000_DBF("DM9000: Read from location which is neither data nor address port: " TARGET_FMT_plx "\n", address);
+ }
+
+ switch(state->address) {
+ case DM9000_REG_NCR:
+ ret = state->dm9k_ncr;
+ break;
+ case DM9000_REG_NSR:
+ ret = state->dm9k_nsr;
+ /* Note, TX1END and TX2END are *CLEAR ON READ* */
+ state->dm9k_nsr &= ~(DM9000_NSR_TX1END | DM9000_NSR_TX2END);
+ break;
+ case DM9000_REG_TCR:
+ ret = state->dm9k_tcr;
+ break;
+ case DM9000_REG_TSR1:
+ case DM9000_REG_TSR2:
+ ret = 0x00; /* No error, yay! */
+ break;
+ case DM9000_REG_EPCR:
+ ret = state->dm9k_epcr;
+ break;
+ case DM9000_REG_EPAR:
+ ret = state->dm9k_epar;
+ break;
+ case DM9000_REG_EPDRL:
+ ret = state->dm9k_epdr & 0xFF;
+ break;
+ case DM9000_REG_EPDRH:
+ ret = (state->dm9k_epdr >> 8) & 0xFF;
+ break;
+ case DM9000_REG_PAR0:
+ case DM9000_REG_PAR1:
+ case DM9000_REG_PAR2:
+ case DM9000_REG_PAR3:
+ case DM9000_REG_PAR4:
+ case DM9000_REG_PAR5:
+ ret = state->macaddr[state->address - DM9000_REG_PAR0];
+ break;
+ case DM9000_REG_MAR0:
+ case DM9000_REG_MAR1:
+ case DM9000_REG_MAR2:
+ case DM9000_REG_MAR3:
+ case DM9000_REG_MAR4:
+ case DM9000_REG_MAR5:
+ case DM9000_REG_MAR6:
+ case DM9000_REG_MAR7:
+ /* multicast hash */
+ ret = state->multihash[state->address - DM9000_REG_MAR0];
+ break;
+ case DM9000_REG_TRPAL:
+ ret = state->dm9k_trpa & 0xFF;
+ break;
+ case DM9000_REG_TRPAH:
+ ret = state->dm9k_trpa >> 8;
+ break;
+ case DM9000_REG_RWPAL:
+ ret = state->dm9k_rwpa & 0xFF;
+ break;
+ case DM9000_REG_RWPAH:
+ ret = state->dm9k_rwpa >> 8;
+ break;
+ case DM9000_REG_VIDL:
+ ret = 0x46;
+ break;
+ case DM9000_REG_VIDH:
+ ret = 0x0A;
+ break;
+ case DM9000_REG_PIDL:
+ ret = 0x00;
+ break;
+ case DM9000_REG_PIDH:
+ ret = 0x90;
+ break;
+ case DM9000_REG_CHIPR:
+ ret = 0x00;
+ break;
+ case DM9000_REG_MRCMDX:
+ case DM9000_REG_MRCMD:
+ /* DM9KNOTE: This assumes a 16bit wide wiring */
+ ret = state->packet_buffer[state->dm9k_mrr];
+ ret |= state->packet_buffer[state->dm9k_mrr+1] << 8;
+ if( state->address == DM9000_REG_MRCMD ) {
+ state->dm9k_mrr += 2;
+ if( state->dm9k_mrr >= (16*1024) ) state->dm9k_mrr -= (16*1024);
+ if( state->dm9k_imr & DM9000_IMR_AUTOWRAP )
+ if( state->dm9k_mrr < 0x0C00 )
+ state->dm9k_mrr += 0x0C00;
+ }
+#ifdef DM9000_DEBUG
+ if (state->address==DM9000_REG_MRCMD)
+ suppress_debug = 1;
+#endif
+ break;
+ case DM9000_REG_MRRL:
+ ret = state->dm9k_mrr & 0xFF;
+ break;
+ case DM9000_REG_MRRH:
+ ret = state->dm9k_mrr >> 8;
+ break;
+ case DM9000_REG_MWRL:
+ ret = state->dm9k_mwr & 0xFF;
+ break;
+ case DM9000_REG_MWRH:
+ ret = state->dm9k_mwr >> 8;
+ break;
+ case DM9000_REG_TXPLL:
+ ret = state->dm9k_txpl & 0xFF;
+ break;
+ case DM9000_REG_TXPLH:
+ ret = state->dm9k_txpl >> 8;
+ break;
+ case DM9000_REG_ISR:
+ ret = state->dm9k_isr;
+ break;
+ case DM9000_REG_IMR:
+ ret = state->dm9k_imr;
+ break;
+ default:
+ ret = 0;
+ }
+
+#ifdef DM9000_DEBUG
+ if(!suppress_debug) DM9000_DBF("DM9000: Read gives: %04x\n", ret);
+#endif
+ return ret;
+}
+
+
+
+static int dm9000_can_receive(void *opaque)
+{
+ dm9000_state *state = (dm9000_state *)opaque;
+ uint16_t rx_space;
+ if( state->dm9k_rwpa < state->dm9k_mrr )
+ rx_space = state->dm9k_mrr - state->dm9k_rwpa;
+ else
+ rx_space = (13*1024) - (state->dm9k_rwpa - state->dm9k_mrr);
+ DM9000_DBF("DM9000:RX_Packet: Asked about RX, rwpa=%d mrr=%d => space is %d bytes\n",
+ state->dm9k_rwpa, state->dm9k_mrr, rx_space);
+ if (rx_space > 2048) return 1;
+ return 0;
+}
+
+static void dm9000_receive(void *opaque, const uint8_t *buf, int size)
+{
+ dm9000_state *state = (dm9000_state *)opaque;
+ uint16_t rxptr = state->dm9k_rwpa;
+ uint8_t magic_padding = 4;
+ if( size > 2048 ) return; /* La La La, I can't hear you */
+ /* Fill out the magical header structure */
+ DM9000_DBF("DM9000:RX_Packet: %d bytes into buffer at %04x\n", size, rxptr);
+ if( size < 64 ) magic_padding += (64 - size);
+ DM9000_DBF("DM9000:RX_Packet: Magical padding is %d bytes\n", magic_padding);
+ size += magic_padding; /* The magical CRC word */
+ state->packet_buffer[state->dm9k_rwpa-4] = 0x01; /* Packet read */
+ state->packet_buffer[state->dm9k_rwpa-3] = 0x00; /* Status OK */
+ state->packet_buffer[state->dm9k_rwpa-2] = size & 0xFF; /* Size LOW */
+ state->packet_buffer[state->dm9k_rwpa-1] = (size & 0xFF00)>>8; /* Size HIGH */
+ size += 4; /* The magical next header (which we zero for fun) */
+ while(size--) {
+ if( size > (magic_padding + 3) )
+ state->packet_buffer[rxptr++] = *buf++;
+ else
+ state->packet_buffer[rxptr++] = 0x00; /* Clear to the next header */
+ /* DM9KNOTE: Assumes 16 bit wired config */
+ if (size == 4) rxptr = (rxptr+1) & ~1; /* At end of packet, realign */
+ if( rxptr >= (16*1024) ) rxptr -= (16*1024);
+ if( rxptr < 0x0C00 ) rxptr += 0x0C00;
+ }
+ state->dm9k_rwpa = rxptr;
+ state->dm9k_isr |= 0x01; /* RX interrupt, yay */
+ dm9000_raise_irq(state);
+}
+
+
+static CPUReadMemoryFunc *dm9000_readfn[] = {
+ dm9000_read,
+ dm9000_read,
+ dm9000_read
+};
+
+static CPUWriteMemoryFunc *dm9000_writefn[] = {
+ dm9000_write,
+ dm9000_write,
+ dm9000_write
+};
+
+/* initialises a dm9000 ethernet controller
+ * The dm9k has a single 16bit wide address and data port through which all
+ * operations are multiplexed, there is a single IRQ
+ */
+void dm9000_init(NICInfo *nd, target_phys_addr_t base_addr,
+ uint32_t addr_offset, uint32_t data_offset,
+ qemu_irq irq)
+{
+ dm9000_state *state;
+ int iomemtype;
+
+ state = (dm9000_state *)qemu_mallocz(sizeof(dm9000_state));
+ iomemtype = cpu_register_io_memory(0, dm9000_readfn,
+ dm9000_writefn, state);
+ cpu_register_physical_memory(base_addr, MAX(addr_offset, data_offset) + 4, iomemtype);
+ state->addr = base_addr + addr_offset;
+ state->data = base_addr + data_offset;
+ state->irq = irq;
+ memcpy(state->macaddr, nd->macaddr, 6);
+
+ dm9000_hard_reset(state);
+
+ state->vc = qemu_new_vlan_client(nd->vlan, dm9000_receive,
+ dm9000_can_receive, state);
+}
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Qemu-devel] [PATCH] DM9000 network card driver
2008-10-27 10:49 [Qemu-devel] [PATCH] DM9000 network card driver Daniel Silverstone
@ 2008-11-10 10:31 ` Daniel Silverstone
2008-11-10 16:47 ` Blue Swirl
0 siblings, 1 reply; 5+ messages in thread
From: Daniel Silverstone @ 2008-11-10 10:31 UTC (permalink / raw)
To: qemu-devel
On Mon, 2008-10-27 at 10:49 +0000, Daniel Silverstone wrote:
> I think this fell through the cracks, so here it is again.
> The Davicom DM9000 10/100 Ethernet controller.
I don't see any replies to this -- it's possible that my list
subscription was playing up at the time, so I thought I'd re-poke about
it.
Basically I'm desperate to know if I'm even going the right way in my
patches -- am I getting them to a state where they could be merged, or
am I wasting my time? Is there an FAQ I need to read which will tell me
how to present these patches in a way which is easier for you all to
deal with them?
I'm just somewhat disheartened that I see patches turn up and get
discussed strongly, and then the updated patches end up being merged,
where after the initial discussion, this patch kinda got dropped on the
floor without an explicit "no" or anything; sitting for two weeks
untouched on-list.
I appreciate that you're all busy, so if the answer is simply "You're on
the list, just it'll be a while" then at least I can carry that back to
my boss who wants to know how it's going getting these patches to you.
Regards,
Daniel.
--
Daniel Silverstone http://www.simtec.co.uk/
PGP mail accepted and encouraged. Key Id: 2BC8 4016 2068 7895
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Qemu-devel] [PATCH] DM9000 network card driver
2008-11-10 10:31 ` Daniel Silverstone
@ 2008-11-10 16:47 ` Blue Swirl
2008-11-11 11:21 ` Daniel Silverstone
0 siblings, 1 reply; 5+ messages in thread
From: Blue Swirl @ 2008-11-10 16:47 UTC (permalink / raw)
To: dsilvers, qemu-devel
On 11/10/08, Daniel Silverstone <dsilvers@simtec.co.uk> wrote:
> On Mon, 2008-10-27 at 10:49 +0000, Daniel Silverstone wrote:
> > I think this fell through the cracks, so here it is again.
> > The Davicom DM9000 10/100 Ethernet controller.
>
> I don't see any replies to this -- it's possible that my list
> subscription was playing up at the time, so I thought I'd re-poke about
> it.
>
> Basically I'm desperate to know if I'm even going the right way in my
> patches -- am I getting them to a state where they could be merged, or
> am I wasting my time? Is there an FAQ I need to read which will tell me
> how to present these patches in a way which is easier for you all to
> deal with them?
>
> I'm just somewhat disheartened that I see patches turn up and get
> discussed strongly, and then the updated patches end up being merged,
> where after the initial discussion, this patch kinda got dropped on the
> floor without an explicit "no" or anything; sitting for two weeks
> untouched on-list.
>
> I appreciate that you're all busy, so if the answer is simply "You're on
> the list, just it'll be a while" then at least I can carry that back to
> my boss who wants to know how it's going getting these patches to you.
Well, for example I could comment on the patches from general point of
view (as I seem to have more time in my hands than some), but then I
don't usually have any means to check if the emulator (or the device)
in question even works with patch applied, or whether the patch makes
sense from the machine architecture POV. For that, the maintainer
should OK the patch.
Your patch looks very clean. I wouldn't use devices.h for the
prototype, but instead some board file (for example arm-misc.h).
The device is not used by any board, so it's not possible even for the
maintainer to test the patch.
As there is a reset function already, it should not be too difficult
to register that for system_reset use.
Save/load functions would be nice, though IIRC ARM boards/devices
don't have any yet.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Qemu-devel] [PATCH] DM9000 network card driver
2008-11-10 16:47 ` Blue Swirl
@ 2008-11-11 11:21 ` Daniel Silverstone
2008-11-11 18:01 ` Blue Swirl
0 siblings, 1 reply; 5+ messages in thread
From: Daniel Silverstone @ 2008-11-11 11:21 UTC (permalink / raw)
To: qemu-devel
On Mon, 2008-11-10 at 18:47 +0200, Blue Swirl wrote:
> > I appreciate that you're all busy, so if the answer is simply "You're on
> > the list, just it'll be a while" then at least I can carry that back to
> > my boss who wants to know how it's going getting these patches to you.
> Your patch looks very clean. I wouldn't use devices.h for the
> prototype, but instead some board file (for example arm-misc.h).
I think I was told to use devices.h quite a while back. It's not
appropriate to put it in arm-misc.h since the device itself has no
specific isolation in ARM stuff. Despite being made to put the HW in the
ARM HW bits of the Makefile.
> The device is not used by any board, so it's not possible even for the
> maintainer to test the patch.
It is used by the board I am trying to get all the patches up-to-snuff
for.
> As there is a reset function already, it should not be too difficult
> to register that for system_reset use.
Can you explain what you mean by that?
> Save/load functions would be nice, though IIRC ARM boards/devices
> don't have any yet.
Some do, some don't -- a portion of what I have already has save/load
support, but this is one device I've not done it for yet. I will
continue to look at that.
Thank you very much for your feedback. Hopefully if you can explain what
this system_reset stuff is, I can get that done and punt a fresh patch
to the list.
Regards,
Daniel.
--
Daniel Silverstone http://www.simtec.co.uk/
PGP mail accepted and encouraged. Key Id: 2BC8 4016 2068 7895
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Qemu-devel] [PATCH] DM9000 network card driver
2008-11-11 11:21 ` Daniel Silverstone
@ 2008-11-11 18:01 ` Blue Swirl
0 siblings, 0 replies; 5+ messages in thread
From: Blue Swirl @ 2008-11-11 18:01 UTC (permalink / raw)
To: dsilvers, qemu-devel
On 11/11/08, Daniel Silverstone <dsilvers@simtec.co.uk> wrote:
> On Mon, 2008-11-10 at 18:47 +0200, Blue Swirl wrote:
> > > I appreciate that you're all busy, so if the answer is simply "You're on
> > > the list, just it'll be a while" then at least I can carry that back to
> > > my boss who wants to know how it's going getting these patches to you.
>
> > Your patch looks very clean. I wouldn't use devices.h for the
> > prototype, but instead some board file (for example arm-misc.h).
>
>
> I think I was told to use devices.h quite a while back. It's not
> appropriate to put it in arm-misc.h since the device itself has no
> specific isolation in ARM stuff. Despite being made to put the HW in the
> ARM HW bits of the Makefile.
I see. Then devices.h seems correct. I was wondering about NEED_CPU stuff.
> > The device is not used by any board, so it's not possible even for the
> > maintainer to test the patch.
>
>
> It is used by the board I am trying to get all the patches up-to-snuff
> for.
Maybe you could add it as an ISA device to PC (pc.c) and see if it works?
> > As there is a reset function already, it should not be too difficult
> > to register that for system_reset use.
>
>
> Can you explain what you mean by that?
Just add a line like
qemu_register_reset(dm9000_hard_reset, state);
to dm9000_init().
Then if the machine gets reset by monitor command "system_reset" or a
hardware device, the reset function will be called to make the device
state predictable like on a real machine.
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2008-11-11 18:01 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-10-27 10:49 [Qemu-devel] [PATCH] DM9000 network card driver Daniel Silverstone
2008-11-10 10:31 ` Daniel Silverstone
2008-11-10 16:47 ` Blue Swirl
2008-11-11 11:21 ` Daniel Silverstone
2008-11-11 18:01 ` Blue Swirl
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).