Split out common pcnet code
The core pcnet emulation code is used by both the PCI "pcnet" device and the SPARC "lance" device. Split the common code frm the PCI code so that that can be configures independantly. Signed-off-by: Paul Brook <paul@codesourcery.com>
This commit is contained in:
parent
129cac5b5a
commit
a4c75a21f3
@ -222,7 +222,8 @@ hw-obj-$(CONFIG_PCI) += pcie.o pcie_port.o
|
||||
# PCI network cards
|
||||
hw-obj-$(CONFIG_NE2000_PCI) += ne2000.o
|
||||
hw-obj-$(CONFIG_EEPRO100_PCI) += eepro100.o
|
||||
hw-obj-$(CONFIG_PCNET_PCI) += pcnet.o
|
||||
hw-obj-$(CONFIG_PCNET_PCI) += pcnet-pci.o
|
||||
hw-obj-$(CONFIG_PCNET_COMMON) += pcnet.o
|
||||
|
||||
hw-obj-$(CONFIG_SMC91C111) += smc91c111.o
|
||||
hw-obj-$(CONFIG_LAN9118) += lan9118.o
|
||||
|
@ -6,6 +6,7 @@ CONFIG_USB_OHCI=y
|
||||
CONFIG_NE2000_PCI=y
|
||||
CONFIG_EEPRO100_PCI=y
|
||||
CONFIG_PCNET_PCI=y
|
||||
CONFIG_PCNET_COMMON=y
|
||||
CONFIG_LSI_SCSI_PCI=y
|
||||
CONFIG_RTL8139_PCI=y
|
||||
CONFIG_E1000_PCI=y
|
||||
|
@ -7,3 +7,4 @@ CONFIG_M48T59=y
|
||||
CONFIG_PTIMER=y
|
||||
CONFIG_FDC=y
|
||||
CONFIG_EMPTY_SLOT=y
|
||||
CONFIG_PCNET_COMMON=y
|
||||
|
311
hw/pcnet.c
311
hw/pcnet.c
@ -35,9 +35,8 @@
|
||||
* http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt
|
||||
*/
|
||||
|
||||
#include "pci.h"
|
||||
#include "qdev.h"
|
||||
#include "net.h"
|
||||
#include "loader.h"
|
||||
#include "qemu-timer.h"
|
||||
#include "qemu_socket.h"
|
||||
|
||||
@ -52,11 +51,6 @@
|
||||
//#define PCNET_DEBUG_MATCH
|
||||
|
||||
|
||||
typedef struct {
|
||||
PCIDevice pci_dev;
|
||||
PCNetState state;
|
||||
} PCIPCNetState;
|
||||
|
||||
struct qemu_ether_header {
|
||||
uint8_t ether_dhost[6];
|
||||
uint8_t ether_shost[6];
|
||||
@ -704,7 +698,6 @@ static void pcnet_poll_timer(void *opaque);
|
||||
static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap);
|
||||
static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value);
|
||||
static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val);
|
||||
static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap);
|
||||
|
||||
static void pcnet_s_reset(PCNetState *s)
|
||||
{
|
||||
@ -1538,7 +1531,7 @@ static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val)
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap)
|
||||
uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap)
|
||||
{
|
||||
uint32_t val;
|
||||
rap &= 127;
|
||||
@ -1595,27 +1588,6 @@ void pcnet_h_reset(void *opaque)
|
||||
pcnet_poll_timer(s);
|
||||
}
|
||||
|
||||
static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val)
|
||||
{
|
||||
PCNetState *s = opaque;
|
||||
#ifdef PCNET_DEBUG
|
||||
printf("pcnet_aprom_writeb addr=0x%08x val=0x%02x\n", addr, val);
|
||||
#endif
|
||||
/* Check APROMWE bit to enable write access */
|
||||
if (pcnet_bcr_readw(s,2) & 0x100)
|
||||
s->prom[addr & 15] = val;
|
||||
}
|
||||
|
||||
static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr)
|
||||
{
|
||||
PCNetState *s = opaque;
|
||||
uint32_t val = s->prom[addr & 15];
|
||||
#ifdef PCNET_DEBUG
|
||||
printf("pcnet_aprom_readb addr=0x%08x val=0x%02x\n", addr, val);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
|
||||
{
|
||||
PCNetState *s = opaque;
|
||||
@ -1668,7 +1640,7 @@ uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr)
|
||||
return val;
|
||||
}
|
||||
|
||||
static void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
|
||||
void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
|
||||
{
|
||||
PCNetState *s = opaque;
|
||||
pcnet_poll_timer(s);
|
||||
@ -1698,7 +1670,7 @@ static void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
|
||||
pcnet_update_irq(s);
|
||||
}
|
||||
|
||||
static uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr)
|
||||
uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr)
|
||||
{
|
||||
PCNetState *s = opaque;
|
||||
uint32_t val = -1;
|
||||
@ -1727,125 +1699,6 @@ static uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr)
|
||||
return val;
|
||||
}
|
||||
|
||||
static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num,
|
||||
pcibus_t addr, pcibus_t size, int type)
|
||||
{
|
||||
PCNetState *d = &DO_UPCAST(PCIPCNetState, pci_dev, pci_dev)->state;
|
||||
|
||||
#ifdef PCNET_DEBUG_IO
|
||||
printf("pcnet_ioport_map addr=0x%04"FMT_PCIBUS" size=0x%04"FMT_PCIBUS"\n",
|
||||
addr, size);
|
||||
#endif
|
||||
|
||||
register_ioport_write(addr, 16, 1, pcnet_aprom_writeb, d);
|
||||
register_ioport_read(addr, 16, 1, pcnet_aprom_readb, d);
|
||||
|
||||
register_ioport_write(addr + 0x10, 0x10, 2, pcnet_ioport_writew, d);
|
||||
register_ioport_read(addr + 0x10, 0x10, 2, pcnet_ioport_readw, d);
|
||||
register_ioport_write(addr + 0x10, 0x10, 4, pcnet_ioport_writel, d);
|
||||
register_ioport_read(addr + 0x10, 0x10, 4, pcnet_ioport_readl, d);
|
||||
}
|
||||
|
||||
static void pcnet_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
PCNetState *d = opaque;
|
||||
#ifdef PCNET_DEBUG_IO
|
||||
printf("pcnet_mmio_writeb addr=0x" TARGET_FMT_plx" val=0x%02x\n", addr,
|
||||
val);
|
||||
#endif
|
||||
if (!(addr & 0x10))
|
||||
pcnet_aprom_writeb(d, addr & 0x0f, val);
|
||||
}
|
||||
|
||||
static uint32_t pcnet_mmio_readb(void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
PCNetState *d = opaque;
|
||||
uint32_t val = -1;
|
||||
if (!(addr & 0x10))
|
||||
val = pcnet_aprom_readb(d, addr & 0x0f);
|
||||
#ifdef PCNET_DEBUG_IO
|
||||
printf("pcnet_mmio_readb addr=0x" TARGET_FMT_plx " val=0x%02x\n", addr,
|
||||
val & 0xff);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
static void pcnet_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
PCNetState *d = opaque;
|
||||
#ifdef PCNET_DEBUG_IO
|
||||
printf("pcnet_mmio_writew addr=0x" TARGET_FMT_plx " val=0x%04x\n", addr,
|
||||
val);
|
||||
#endif
|
||||
if (addr & 0x10)
|
||||
pcnet_ioport_writew(d, addr & 0x0f, val);
|
||||
else {
|
||||
addr &= 0x0f;
|
||||
pcnet_aprom_writeb(d, addr, val & 0xff);
|
||||
pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t pcnet_mmio_readw(void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
PCNetState *d = opaque;
|
||||
uint32_t val = -1;
|
||||
if (addr & 0x10)
|
||||
val = pcnet_ioport_readw(d, addr & 0x0f);
|
||||
else {
|
||||
addr &= 0x0f;
|
||||
val = pcnet_aprom_readb(d, addr+1);
|
||||
val <<= 8;
|
||||
val |= pcnet_aprom_readb(d, addr);
|
||||
}
|
||||
#ifdef PCNET_DEBUG_IO
|
||||
printf("pcnet_mmio_readw addr=0x" TARGET_FMT_plx" val = 0x%04x\n", addr,
|
||||
val & 0xffff);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
static void pcnet_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
PCNetState *d = opaque;
|
||||
#ifdef PCNET_DEBUG_IO
|
||||
printf("pcnet_mmio_writel addr=0x" TARGET_FMT_plx" val=0x%08x\n", addr,
|
||||
val);
|
||||
#endif
|
||||
if (addr & 0x10)
|
||||
pcnet_ioport_writel(d, addr & 0x0f, val);
|
||||
else {
|
||||
addr &= 0x0f;
|
||||
pcnet_aprom_writeb(d, addr, val & 0xff);
|
||||
pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8);
|
||||
pcnet_aprom_writeb(d, addr+2, (val & 0xff0000) >> 16);
|
||||
pcnet_aprom_writeb(d, addr+3, (val & 0xff000000) >> 24);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t pcnet_mmio_readl(void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
PCNetState *d = opaque;
|
||||
uint32_t val;
|
||||
if (addr & 0x10)
|
||||
val = pcnet_ioport_readl(d, addr & 0x0f);
|
||||
else {
|
||||
addr &= 0x0f;
|
||||
val = pcnet_aprom_readb(d, addr+3);
|
||||
val <<= 8;
|
||||
val |= pcnet_aprom_readb(d, addr+2);
|
||||
val <<= 8;
|
||||
val |= pcnet_aprom_readb(d, addr+1);
|
||||
val <<= 8;
|
||||
val |= pcnet_aprom_readb(d, addr);
|
||||
}
|
||||
#ifdef PCNET_DEBUG_IO
|
||||
printf("pcnet_mmio_readl addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr,
|
||||
val);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
static bool is_version_2(void *opaque, int version_id)
|
||||
{
|
||||
return version_id == 2;
|
||||
@ -1875,18 +1728,6 @@ const VMStateDescription vmstate_pcnet = {
|
||||
}
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_pci_pcnet = {
|
||||
.name = "pcnet",
|
||||
.version_id = 3,
|
||||
.minimum_version_id = 2,
|
||||
.minimum_version_id_old = 2,
|
||||
.fields = (VMStateField []) {
|
||||
VMSTATE_PCI_DEVICE(pci_dev, PCIPCNetState),
|
||||
VMSTATE_STRUCT(state, PCIPCNetState, 0, vmstate_pcnet, PCNetState),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
void pcnet_common_cleanup(PCNetState *d)
|
||||
{
|
||||
d->nic = NULL;
|
||||
@ -1901,147 +1742,3 @@ int pcnet_common_init(DeviceState *dev, PCNetState *s, NetClientInfo *info)
|
||||
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* PCI interface */
|
||||
|
||||
static CPUWriteMemoryFunc * const pcnet_mmio_write[] = {
|
||||
&pcnet_mmio_writeb,
|
||||
&pcnet_mmio_writew,
|
||||
&pcnet_mmio_writel
|
||||
};
|
||||
|
||||
static CPUReadMemoryFunc * const pcnet_mmio_read[] = {
|
||||
&pcnet_mmio_readb,
|
||||
&pcnet_mmio_readw,
|
||||
&pcnet_mmio_readl
|
||||
};
|
||||
|
||||
static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num,
|
||||
pcibus_t addr, pcibus_t size, int type)
|
||||
{
|
||||
PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev);
|
||||
|
||||
#ifdef PCNET_DEBUG_IO
|
||||
printf("pcnet_mmio_map addr=0x%08"FMT_PCIBUS" 0x%08"FMT_PCIBUS"\n",
|
||||
addr, size);
|
||||
#endif
|
||||
|
||||
cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->state.mmio_index);
|
||||
}
|
||||
|
||||
static void pci_physical_memory_write(void *dma_opaque, target_phys_addr_t addr,
|
||||
uint8_t *buf, int len, int do_bswap)
|
||||
{
|
||||
cpu_physical_memory_write(addr, buf, len);
|
||||
}
|
||||
|
||||
static void pci_physical_memory_read(void *dma_opaque, target_phys_addr_t addr,
|
||||
uint8_t *buf, int len, int do_bswap)
|
||||
{
|
||||
cpu_physical_memory_read(addr, buf, len);
|
||||
}
|
||||
|
||||
static void pci_pcnet_cleanup(VLANClientState *nc)
|
||||
{
|
||||
PCNetState *d = DO_UPCAST(NICState, nc, nc)->opaque;
|
||||
|
||||
pcnet_common_cleanup(d);
|
||||
}
|
||||
|
||||
static int pci_pcnet_uninit(PCIDevice *dev)
|
||||
{
|
||||
PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, dev);
|
||||
|
||||
cpu_unregister_io_memory(d->state.mmio_index);
|
||||
qemu_del_timer(d->state.poll_timer);
|
||||
qemu_free_timer(d->state.poll_timer);
|
||||
qemu_del_vlan_client(&d->state.nic->nc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static NetClientInfo net_pci_pcnet_info = {
|
||||
.type = NET_CLIENT_TYPE_NIC,
|
||||
.size = sizeof(NICState),
|
||||
.can_receive = pcnet_can_receive,
|
||||
.receive = pcnet_receive,
|
||||
.cleanup = pci_pcnet_cleanup,
|
||||
};
|
||||
|
||||
static int pci_pcnet_init(PCIDevice *pci_dev)
|
||||
{
|
||||
PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev);
|
||||
PCNetState *s = &d->state;
|
||||
uint8_t *pci_conf;
|
||||
|
||||
#if 0
|
||||
printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n",
|
||||
sizeof(struct pcnet_RMD), sizeof(struct pcnet_TMD));
|
||||
#endif
|
||||
|
||||
pci_conf = pci_dev->config;
|
||||
|
||||
pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_AMD);
|
||||
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_AMD_LANCE);
|
||||
pci_set_word(pci_conf + PCI_STATUS,
|
||||
PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM);
|
||||
pci_conf[PCI_REVISION_ID] = 0x10;
|
||||
pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
|
||||
|
||||
pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, 0x0);
|
||||
pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0);
|
||||
|
||||
pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0
|
||||
pci_conf[PCI_MIN_GNT] = 0x06;
|
||||
pci_conf[PCI_MAX_LAT] = 0xff;
|
||||
|
||||
/* Handler for memory-mapped I/O */
|
||||
s->mmio_index =
|
||||
cpu_register_io_memory(pcnet_mmio_read, pcnet_mmio_write, &d->state);
|
||||
|
||||
pci_register_bar(pci_dev, 0, PCNET_IOPORT_SIZE,
|
||||
PCI_BASE_ADDRESS_SPACE_IO, pcnet_ioport_map);
|
||||
|
||||
pci_register_bar(pci_dev, 1, PCNET_PNPMMIO_SIZE,
|
||||
PCI_BASE_ADDRESS_SPACE_MEMORY, pcnet_mmio_map);
|
||||
|
||||
s->irq = pci_dev->irq[0];
|
||||
s->phys_mem_read = pci_physical_memory_read;
|
||||
s->phys_mem_write = pci_physical_memory_write;
|
||||
|
||||
if (!pci_dev->qdev.hotplugged) {
|
||||
static int loaded = 0;
|
||||
if (!loaded) {
|
||||
rom_add_option("pxe-pcnet.bin");
|
||||
loaded = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return pcnet_common_init(&pci_dev->qdev, s, &net_pci_pcnet_info);
|
||||
}
|
||||
|
||||
static void pci_reset(DeviceState *dev)
|
||||
{
|
||||
PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev.qdev, dev);
|
||||
|
||||
pcnet_h_reset(&d->state);
|
||||
}
|
||||
|
||||
static PCIDeviceInfo pcnet_info = {
|
||||
.qdev.name = "pcnet",
|
||||
.qdev.size = sizeof(PCIPCNetState),
|
||||
.qdev.reset = pci_reset,
|
||||
.qdev.vmsd = &vmstate_pci_pcnet,
|
||||
.init = pci_pcnet_init,
|
||||
.exit = pci_pcnet_uninit,
|
||||
.qdev.props = (Property[]) {
|
||||
DEFINE_NIC_PROPERTIES(PCIPCNetState, state.conf),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
}
|
||||
};
|
||||
|
||||
static void pcnet_register_devices(void)
|
||||
{
|
||||
pci_qdev_register(&pcnet_info);
|
||||
}
|
||||
|
||||
device_init(pcnet_register_devices)
|
||||
|
@ -32,6 +32,9 @@ struct PCNetState_st {
|
||||
void pcnet_h_reset(void *opaque);
|
||||
void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val);
|
||||
uint32_t pcnet_ioport_readw(void *opaque, uint32_t addr);
|
||||
void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val);
|
||||
uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr);
|
||||
uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap);
|
||||
int pcnet_can_receive(VLANClientState *nc);
|
||||
ssize_t pcnet_receive(VLANClientState *nc, const uint8_t *buf, size_t size_);
|
||||
void pcnet_common_cleanup(PCNetState *d);
|
||||
|
Loading…
Reference in New Issue
Block a user