Revision a4c75a21 hw/pcnet.c
b/hw/pcnet.c | ||
---|---|---|
35 | 35 |
* http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt |
36 | 36 |
*/ |
37 | 37 |
|
38 |
#include "pci.h"
|
|
38 |
#include "qdev.h"
|
|
39 | 39 |
#include "net.h" |
40 |
#include "loader.h" |
|
41 | 40 |
#include "qemu-timer.h" |
42 | 41 |
#include "qemu_socket.h" |
43 | 42 |
|
... | ... | |
52 | 51 |
//#define PCNET_DEBUG_MATCH |
53 | 52 |
|
54 | 53 |
|
55 |
typedef struct { |
|
56 |
PCIDevice pci_dev; |
|
57 |
PCNetState state; |
|
58 |
} PCIPCNetState; |
|
59 |
|
|
60 | 54 |
struct qemu_ether_header { |
61 | 55 |
uint8_t ether_dhost[6]; |
62 | 56 |
uint8_t ether_shost[6]; |
... | ... | |
704 | 698 |
static uint32_t pcnet_csr_readw(PCNetState *s, uint32_t rap); |
705 | 699 |
static void pcnet_csr_writew(PCNetState *s, uint32_t rap, uint32_t new_value); |
706 | 700 |
static void pcnet_bcr_writew(PCNetState *s, uint32_t rap, uint32_t val); |
707 |
static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap); |
|
708 | 701 |
|
709 | 702 |
static void pcnet_s_reset(PCNetState *s) |
710 | 703 |
{ |
... | ... | |
1538 | 1531 |
} |
1539 | 1532 |
} |
1540 | 1533 |
|
1541 |
static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap)
|
|
1534 |
uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap) |
|
1542 | 1535 |
{ |
1543 | 1536 |
uint32_t val; |
1544 | 1537 |
rap &= 127; |
... | ... | |
1595 | 1588 |
pcnet_poll_timer(s); |
1596 | 1589 |
} |
1597 | 1590 |
|
1598 |
static void pcnet_aprom_writeb(void *opaque, uint32_t addr, uint32_t val) |
|
1599 |
{ |
|
1600 |
PCNetState *s = opaque; |
|
1601 |
#ifdef PCNET_DEBUG |
|
1602 |
printf("pcnet_aprom_writeb addr=0x%08x val=0x%02x\n", addr, val); |
|
1603 |
#endif |
|
1604 |
/* Check APROMWE bit to enable write access */ |
|
1605 |
if (pcnet_bcr_readw(s,2) & 0x100) |
|
1606 |
s->prom[addr & 15] = val; |
|
1607 |
} |
|
1608 |
|
|
1609 |
static uint32_t pcnet_aprom_readb(void *opaque, uint32_t addr) |
|
1610 |
{ |
|
1611 |
PCNetState *s = opaque; |
|
1612 |
uint32_t val = s->prom[addr & 15]; |
|
1613 |
#ifdef PCNET_DEBUG |
|
1614 |
printf("pcnet_aprom_readb addr=0x%08x val=0x%02x\n", addr, val); |
|
1615 |
#endif |
|
1616 |
return val; |
|
1617 |
} |
|
1618 |
|
|
1619 | 1591 |
void pcnet_ioport_writew(void *opaque, uint32_t addr, uint32_t val) |
1620 | 1592 |
{ |
1621 | 1593 |
PCNetState *s = opaque; |
... | ... | |
1668 | 1640 |
return val; |
1669 | 1641 |
} |
1670 | 1642 |
|
1671 |
static void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val)
|
|
1643 |
void pcnet_ioport_writel(void *opaque, uint32_t addr, uint32_t val) |
|
1672 | 1644 |
{ |
1673 | 1645 |
PCNetState *s = opaque; |
1674 | 1646 |
pcnet_poll_timer(s); |
... | ... | |
1698 | 1670 |
pcnet_update_irq(s); |
1699 | 1671 |
} |
1700 | 1672 |
|
1701 |
static uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr)
|
|
1673 |
uint32_t pcnet_ioport_readl(void *opaque, uint32_t addr) |
|
1702 | 1674 |
{ |
1703 | 1675 |
PCNetState *s = opaque; |
1704 | 1676 |
uint32_t val = -1; |
... | ... | |
1727 | 1699 |
return val; |
1728 | 1700 |
} |
1729 | 1701 |
|
1730 |
static void pcnet_ioport_map(PCIDevice *pci_dev, int region_num, |
|
1731 |
pcibus_t addr, pcibus_t size, int type) |
|
1732 |
{ |
|
1733 |
PCNetState *d = &DO_UPCAST(PCIPCNetState, pci_dev, pci_dev)->state; |
|
1734 |
|
|
1735 |
#ifdef PCNET_DEBUG_IO |
|
1736 |
printf("pcnet_ioport_map addr=0x%04"FMT_PCIBUS" size=0x%04"FMT_PCIBUS"\n", |
|
1737 |
addr, size); |
|
1738 |
#endif |
|
1739 |
|
|
1740 |
register_ioport_write(addr, 16, 1, pcnet_aprom_writeb, d); |
|
1741 |
register_ioport_read(addr, 16, 1, pcnet_aprom_readb, d); |
|
1742 |
|
|
1743 |
register_ioport_write(addr + 0x10, 0x10, 2, pcnet_ioport_writew, d); |
|
1744 |
register_ioport_read(addr + 0x10, 0x10, 2, pcnet_ioport_readw, d); |
|
1745 |
register_ioport_write(addr + 0x10, 0x10, 4, pcnet_ioport_writel, d); |
|
1746 |
register_ioport_read(addr + 0x10, 0x10, 4, pcnet_ioport_readl, d); |
|
1747 |
} |
|
1748 |
|
|
1749 |
static void pcnet_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) |
|
1750 |
{ |
|
1751 |
PCNetState *d = opaque; |
|
1752 |
#ifdef PCNET_DEBUG_IO |
|
1753 |
printf("pcnet_mmio_writeb addr=0x" TARGET_FMT_plx" val=0x%02x\n", addr, |
|
1754 |
val); |
|
1755 |
#endif |
|
1756 |
if (!(addr & 0x10)) |
|
1757 |
pcnet_aprom_writeb(d, addr & 0x0f, val); |
|
1758 |
} |
|
1759 |
|
|
1760 |
static uint32_t pcnet_mmio_readb(void *opaque, target_phys_addr_t addr) |
|
1761 |
{ |
|
1762 |
PCNetState *d = opaque; |
|
1763 |
uint32_t val = -1; |
|
1764 |
if (!(addr & 0x10)) |
|
1765 |
val = pcnet_aprom_readb(d, addr & 0x0f); |
|
1766 |
#ifdef PCNET_DEBUG_IO |
|
1767 |
printf("pcnet_mmio_readb addr=0x" TARGET_FMT_plx " val=0x%02x\n", addr, |
|
1768 |
val & 0xff); |
|
1769 |
#endif |
|
1770 |
return val; |
|
1771 |
} |
|
1772 |
|
|
1773 |
static void pcnet_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val) |
|
1774 |
{ |
|
1775 |
PCNetState *d = opaque; |
|
1776 |
#ifdef PCNET_DEBUG_IO |
|
1777 |
printf("pcnet_mmio_writew addr=0x" TARGET_FMT_plx " val=0x%04x\n", addr, |
|
1778 |
val); |
|
1779 |
#endif |
|
1780 |
if (addr & 0x10) |
|
1781 |
pcnet_ioport_writew(d, addr & 0x0f, val); |
|
1782 |
else { |
|
1783 |
addr &= 0x0f; |
|
1784 |
pcnet_aprom_writeb(d, addr, val & 0xff); |
|
1785 |
pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8); |
|
1786 |
} |
|
1787 |
} |
|
1788 |
|
|
1789 |
static uint32_t pcnet_mmio_readw(void *opaque, target_phys_addr_t addr) |
|
1790 |
{ |
|
1791 |
PCNetState *d = opaque; |
|
1792 |
uint32_t val = -1; |
|
1793 |
if (addr & 0x10) |
|
1794 |
val = pcnet_ioport_readw(d, addr & 0x0f); |
|
1795 |
else { |
|
1796 |
addr &= 0x0f; |
|
1797 |
val = pcnet_aprom_readb(d, addr+1); |
|
1798 |
val <<= 8; |
|
1799 |
val |= pcnet_aprom_readb(d, addr); |
|
1800 |
} |
|
1801 |
#ifdef PCNET_DEBUG_IO |
|
1802 |
printf("pcnet_mmio_readw addr=0x" TARGET_FMT_plx" val = 0x%04x\n", addr, |
|
1803 |
val & 0xffff); |
|
1804 |
#endif |
|
1805 |
return val; |
|
1806 |
} |
|
1807 |
|
|
1808 |
static void pcnet_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val) |
|
1809 |
{ |
|
1810 |
PCNetState *d = opaque; |
|
1811 |
#ifdef PCNET_DEBUG_IO |
|
1812 |
printf("pcnet_mmio_writel addr=0x" TARGET_FMT_plx" val=0x%08x\n", addr, |
|
1813 |
val); |
|
1814 |
#endif |
|
1815 |
if (addr & 0x10) |
|
1816 |
pcnet_ioport_writel(d, addr & 0x0f, val); |
|
1817 |
else { |
|
1818 |
addr &= 0x0f; |
|
1819 |
pcnet_aprom_writeb(d, addr, val & 0xff); |
|
1820 |
pcnet_aprom_writeb(d, addr+1, (val & 0xff00) >> 8); |
|
1821 |
pcnet_aprom_writeb(d, addr+2, (val & 0xff0000) >> 16); |
|
1822 |
pcnet_aprom_writeb(d, addr+3, (val & 0xff000000) >> 24); |
|
1823 |
} |
|
1824 |
} |
|
1825 |
|
|
1826 |
static uint32_t pcnet_mmio_readl(void *opaque, target_phys_addr_t addr) |
|
1827 |
{ |
|
1828 |
PCNetState *d = opaque; |
|
1829 |
uint32_t val; |
|
1830 |
if (addr & 0x10) |
|
1831 |
val = pcnet_ioport_readl(d, addr & 0x0f); |
|
1832 |
else { |
|
1833 |
addr &= 0x0f; |
|
1834 |
val = pcnet_aprom_readb(d, addr+3); |
|
1835 |
val <<= 8; |
|
1836 |
val |= pcnet_aprom_readb(d, addr+2); |
|
1837 |
val <<= 8; |
|
1838 |
val |= pcnet_aprom_readb(d, addr+1); |
|
1839 |
val <<= 8; |
|
1840 |
val |= pcnet_aprom_readb(d, addr); |
|
1841 |
} |
|
1842 |
#ifdef PCNET_DEBUG_IO |
|
1843 |
printf("pcnet_mmio_readl addr=0x" TARGET_FMT_plx " val=0x%08x\n", addr, |
|
1844 |
val); |
|
1845 |
#endif |
|
1846 |
return val; |
|
1847 |
} |
|
1848 |
|
|
1849 | 1702 |
static bool is_version_2(void *opaque, int version_id) |
1850 | 1703 |
{ |
1851 | 1704 |
return version_id == 2; |
... | ... | |
1875 | 1728 |
} |
1876 | 1729 |
}; |
1877 | 1730 |
|
1878 |
static const VMStateDescription vmstate_pci_pcnet = { |
|
1879 |
.name = "pcnet", |
|
1880 |
.version_id = 3, |
|
1881 |
.minimum_version_id = 2, |
|
1882 |
.minimum_version_id_old = 2, |
|
1883 |
.fields = (VMStateField []) { |
|
1884 |
VMSTATE_PCI_DEVICE(pci_dev, PCIPCNetState), |
|
1885 |
VMSTATE_STRUCT(state, PCIPCNetState, 0, vmstate_pcnet, PCNetState), |
|
1886 |
VMSTATE_END_OF_LIST() |
|
1887 |
} |
|
1888 |
}; |
|
1889 |
|
|
1890 | 1731 |
void pcnet_common_cleanup(PCNetState *d) |
1891 | 1732 |
{ |
1892 | 1733 |
d->nic = NULL; |
... | ... | |
1901 | 1742 |
qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a); |
1902 | 1743 |
return 0; |
1903 | 1744 |
} |
1904 |
|
|
1905 |
/* PCI interface */ |
|
1906 |
|
|
1907 |
static CPUWriteMemoryFunc * const pcnet_mmio_write[] = { |
|
1908 |
&pcnet_mmio_writeb, |
|
1909 |
&pcnet_mmio_writew, |
|
1910 |
&pcnet_mmio_writel |
|
1911 |
}; |
|
1912 |
|
|
1913 |
static CPUReadMemoryFunc * const pcnet_mmio_read[] = { |
|
1914 |
&pcnet_mmio_readb, |
|
1915 |
&pcnet_mmio_readw, |
|
1916 |
&pcnet_mmio_readl |
|
1917 |
}; |
|
1918 |
|
|
1919 |
static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num, |
|
1920 |
pcibus_t addr, pcibus_t size, int type) |
|
1921 |
{ |
|
1922 |
PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev); |
|
1923 |
|
|
1924 |
#ifdef PCNET_DEBUG_IO |
|
1925 |
printf("pcnet_mmio_map addr=0x%08"FMT_PCIBUS" 0x%08"FMT_PCIBUS"\n", |
|
1926 |
addr, size); |
|
1927 |
#endif |
|
1928 |
|
|
1929 |
cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->state.mmio_index); |
|
1930 |
} |
|
1931 |
|
|
1932 |
static void pci_physical_memory_write(void *dma_opaque, target_phys_addr_t addr, |
|
1933 |
uint8_t *buf, int len, int do_bswap) |
|
1934 |
{ |
|
1935 |
cpu_physical_memory_write(addr, buf, len); |
|
1936 |
} |
|
1937 |
|
|
1938 |
static void pci_physical_memory_read(void *dma_opaque, target_phys_addr_t addr, |
|
1939 |
uint8_t *buf, int len, int do_bswap) |
|
1940 |
{ |
|
1941 |
cpu_physical_memory_read(addr, buf, len); |
|
1942 |
} |
|
1943 |
|
|
1944 |
static void pci_pcnet_cleanup(VLANClientState *nc) |
|
1945 |
{ |
|
1946 |
PCNetState *d = DO_UPCAST(NICState, nc, nc)->opaque; |
|
1947 |
|
|
1948 |
pcnet_common_cleanup(d); |
|
1949 |
} |
|
1950 |
|
|
1951 |
static int pci_pcnet_uninit(PCIDevice *dev) |
|
1952 |
{ |
|
1953 |
PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, dev); |
|
1954 |
|
|
1955 |
cpu_unregister_io_memory(d->state.mmio_index); |
|
1956 |
qemu_del_timer(d->state.poll_timer); |
|
1957 |
qemu_free_timer(d->state.poll_timer); |
|
1958 |
qemu_del_vlan_client(&d->state.nic->nc); |
|
1959 |
return 0; |
|
1960 |
} |
|
1961 |
|
|
1962 |
static NetClientInfo net_pci_pcnet_info = { |
|
1963 |
.type = NET_CLIENT_TYPE_NIC, |
|
1964 |
.size = sizeof(NICState), |
|
1965 |
.can_receive = pcnet_can_receive, |
|
1966 |
.receive = pcnet_receive, |
|
1967 |
.cleanup = pci_pcnet_cleanup, |
|
1968 |
}; |
|
1969 |
|
|
1970 |
static int pci_pcnet_init(PCIDevice *pci_dev) |
|
1971 |
{ |
|
1972 |
PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev, pci_dev); |
|
1973 |
PCNetState *s = &d->state; |
|
1974 |
uint8_t *pci_conf; |
|
1975 |
|
|
1976 |
#if 0 |
|
1977 |
printf("sizeof(RMD)=%d, sizeof(TMD)=%d\n", |
|
1978 |
sizeof(struct pcnet_RMD), sizeof(struct pcnet_TMD)); |
|
1979 |
#endif |
|
1980 |
|
|
1981 |
pci_conf = pci_dev->config; |
|
1982 |
|
|
1983 |
pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_AMD); |
|
1984 |
pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_AMD_LANCE); |
|
1985 |
pci_set_word(pci_conf + PCI_STATUS, |
|
1986 |
PCI_STATUS_FAST_BACK | PCI_STATUS_DEVSEL_MEDIUM); |
|
1987 |
pci_conf[PCI_REVISION_ID] = 0x10; |
|
1988 |
pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET); |
|
1989 |
|
|
1990 |
pci_set_word(pci_conf + PCI_SUBSYSTEM_VENDOR_ID, 0x0); |
|
1991 |
pci_set_word(pci_conf + PCI_SUBSYSTEM_ID, 0x0); |
|
1992 |
|
|
1993 |
pci_conf[PCI_INTERRUPT_PIN] = 1; // interrupt pin 0 |
|
1994 |
pci_conf[PCI_MIN_GNT] = 0x06; |
|
1995 |
pci_conf[PCI_MAX_LAT] = 0xff; |
|
1996 |
|
|
1997 |
/* Handler for memory-mapped I/O */ |
|
1998 |
s->mmio_index = |
|
1999 |
cpu_register_io_memory(pcnet_mmio_read, pcnet_mmio_write, &d->state); |
|
2000 |
|
|
2001 |
pci_register_bar(pci_dev, 0, PCNET_IOPORT_SIZE, |
|
2002 |
PCI_BASE_ADDRESS_SPACE_IO, pcnet_ioport_map); |
|
2003 |
|
|
2004 |
pci_register_bar(pci_dev, 1, PCNET_PNPMMIO_SIZE, |
|
2005 |
PCI_BASE_ADDRESS_SPACE_MEMORY, pcnet_mmio_map); |
|
2006 |
|
|
2007 |
s->irq = pci_dev->irq[0]; |
|
2008 |
s->phys_mem_read = pci_physical_memory_read; |
|
2009 |
s->phys_mem_write = pci_physical_memory_write; |
|
2010 |
|
|
2011 |
if (!pci_dev->qdev.hotplugged) { |
|
2012 |
static int loaded = 0; |
|
2013 |
if (!loaded) { |
|
2014 |
rom_add_option("pxe-pcnet.bin"); |
|
2015 |
loaded = 1; |
|
2016 |
} |
|
2017 |
} |
|
2018 |
|
|
2019 |
return pcnet_common_init(&pci_dev->qdev, s, &net_pci_pcnet_info); |
|
2020 |
} |
|
2021 |
|
|
2022 |
static void pci_reset(DeviceState *dev) |
|
2023 |
{ |
|
2024 |
PCIPCNetState *d = DO_UPCAST(PCIPCNetState, pci_dev.qdev, dev); |
|
2025 |
|
|
2026 |
pcnet_h_reset(&d->state); |
|
2027 |
} |
|
2028 |
|
|
2029 |
static PCIDeviceInfo pcnet_info = { |
|
2030 |
.qdev.name = "pcnet", |
|
2031 |
.qdev.size = sizeof(PCIPCNetState), |
|
2032 |
.qdev.reset = pci_reset, |
|
2033 |
.qdev.vmsd = &vmstate_pci_pcnet, |
|
2034 |
.init = pci_pcnet_init, |
|
2035 |
.exit = pci_pcnet_uninit, |
|
2036 |
.qdev.props = (Property[]) { |
|
2037 |
DEFINE_NIC_PROPERTIES(PCIPCNetState, state.conf), |
|
2038 |
DEFINE_PROP_END_OF_LIST(), |
|
2039 |
} |
|
2040 |
}; |
|
2041 |
|
|
2042 |
static void pcnet_register_devices(void) |
|
2043 |
{ |
|
2044 |
pci_qdev_register(&pcnet_info); |
|
2045 |
} |
|
2046 |
|
|
2047 |
device_init(pcnet_register_devices) |
Also available in: Unified diff