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)
|