-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1 iQEcBAABAgAGBQJYgXzxAAoJEO8Ells5jWIRgtAIAKuFrOBE/xJnjd/45sVKcx2j fsohKHF8T/eLmt5sw+MhGtnM/oRJRUX8kGpA9AU8m6TCSaTYh2tOKX5lwrykuAzk feqz2pqZFwiLWs5Ro7qEQIhMkqtFetODvKd05qnKnAldj8SC45czKxdghmSP/B+w 4nnDEdqVqUuUseDCa1mW1b4f6g1N93LbgChK7lK9Xqg+OqeEbQ7nLgVvcWvN7+Ea DfDKWP8tjQ5QhjzFWc4wa9/Tx+0HI7Dn57fv98XdJMvm1kt/MdnO7QKAXWmHH5s/ 6DX+NHgN0ZAn85gv/ufq1F9C4TstbAoZA9EOGhoBJ5ww8mueARB3L2iCj+OcS9A= =gkbh -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/jasowang/tags/net-pull-request' into staging # gpg: Signature made Fri 20 Jan 2017 02:58:57 GMT # gpg: using RSA key 0xEF04965B398D6211 # gpg: Good signature from "Jason Wang (Jason Wang on RedHat) <jasowang@redhat.com>" # gpg: WARNING: This key is not certified with sufficiently trusted signatures! # gpg: It is not certain that the signature belongs to the owner. # Primary key fingerprint: 215D 46F4 8246 689E C77F 3562 EF04 965B 398D 6211 * remotes/jasowang/tags/net-pull-request: tap: fix memory leak on failure in net_init_tap() hw/pci: use-after-free in pci_nic_init_nofail when nic device fails to initialize hw/net/dp8393x: Avoid unintentional sign extensions on addresses m68k: QOMify the MCF Fast Ethernet Controller device net: optimize checksum computation docs: Fix description of the sentence Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
db655a9653
@ -158,7 +158,9 @@ secondary.
|
|||||||
|
|
||||||
== Usage ==
|
== Usage ==
|
||||||
|
|
||||||
Here, we use demo ip and port discribe more clearly.
|
Here is an example using demonstration IP and port addresses to more
|
||||||
|
clearly describe the usage.
|
||||||
|
|
||||||
Primary(ip:3.3.3.3):
|
Primary(ip:3.3.3.3):
|
||||||
-netdev tap,id=hn0,vhost=off,script=/etc/qemu-ifup,downscript=/etc/qemu-ifdown
|
-netdev tap,id=hn0,vhost=off,script=/etc/qemu-ifup,downscript=/etc/qemu-ifdown
|
||||||
-device e1000,id=e0,netdev=hn0,mac=52:a4:00:12:78:66
|
-device e1000,id=e0,netdev=hn0,mac=52:a4:00:12:78:66
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
#include "hw/hw.h"
|
#include "hw/hw.h"
|
||||||
#include "hw/m68k/mcf.h"
|
#include "hw/m68k/mcf.h"
|
||||||
|
#include "hw/m68k/mcf_fec.h"
|
||||||
#include "qemu/timer.h"
|
#include "qemu/timer.h"
|
||||||
#include "hw/ptimer.h"
|
#include "hw/ptimer.h"
|
||||||
#include "sysemu/sysemu.h"
|
#include "sysemu/sysemu.h"
|
||||||
@ -18,6 +19,7 @@
|
|||||||
#include "net/net.h"
|
#include "net/net.h"
|
||||||
#include "hw/boards.h"
|
#include "hw/boards.h"
|
||||||
#include "hw/loader.h"
|
#include "hw/loader.h"
|
||||||
|
#include "hw/sysbus.h"
|
||||||
#include "elf.h"
|
#include "elf.h"
|
||||||
#include "exec/address-spaces.h"
|
#include "exec/address-spaces.h"
|
||||||
|
|
||||||
@ -192,6 +194,26 @@ static void mcf5208_sys_init(MemoryRegion *address_space, qemu_irq *pic)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void mcf_fec_init(MemoryRegion *sysmem, NICInfo *nd, hwaddr base,
|
||||||
|
qemu_irq *irqs)
|
||||||
|
{
|
||||||
|
DeviceState *dev;
|
||||||
|
SysBusDevice *s;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
qemu_check_nic_model(nd, TYPE_MCF_FEC_NET);
|
||||||
|
dev = qdev_create(NULL, TYPE_MCF_FEC_NET);
|
||||||
|
qdev_set_nic_properties(dev, nd);
|
||||||
|
qdev_init_nofail(dev);
|
||||||
|
|
||||||
|
s = SYS_BUS_DEVICE(dev);
|
||||||
|
for (i = 0; i < FEC_NUM_IRQ; i++) {
|
||||||
|
sysbus_connect_irq(s, i, irqs[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
memory_region_add_subregion(sysmem, base, sysbus_mmio_get_region(s, 0));
|
||||||
|
}
|
||||||
|
|
||||||
static void mcf5208evb_init(MachineState *machine)
|
static void mcf5208evb_init(MachineState *machine)
|
||||||
{
|
{
|
||||||
ram_addr_t ram_size = machine->ram_size;
|
ram_addr_t ram_size = machine->ram_size;
|
||||||
@ -243,9 +265,10 @@ static void mcf5208evb_init(MachineState *machine)
|
|||||||
fprintf(stderr, "Too many NICs\n");
|
fprintf(stderr, "Too many NICs\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if (nd_table[0].used)
|
if (nd_table[0].used) {
|
||||||
mcf_fec_init(address_space_mem, &nd_table[0],
|
mcf_fec_init(address_space_mem, &nd_table[0],
|
||||||
0xfc030000, pic + 36);
|
0xfc030000, pic + 36);
|
||||||
|
}
|
||||||
|
|
||||||
/* 0xfc000000 SCM. */
|
/* 0xfc000000 SCM. */
|
||||||
/* 0xfc004000 XBS. */
|
/* 0xfc004000 XBS. */
|
||||||
|
@ -174,6 +174,52 @@ typedef struct dp8393xState {
|
|||||||
AddressSpace as;
|
AddressSpace as;
|
||||||
} dp8393xState;
|
} dp8393xState;
|
||||||
|
|
||||||
|
/* Accessor functions for values which are formed by
|
||||||
|
* concatenating two 16 bit device registers. By putting these
|
||||||
|
* in their own functions with a uint32_t return type we avoid the
|
||||||
|
* pitfall of implicit sign extension where ((x << 16) | y) is a
|
||||||
|
* signed 32 bit integer that might get sign-extended to a 64 bit integer.
|
||||||
|
*/
|
||||||
|
static uint32_t dp8393x_cdp(dp8393xState *s)
|
||||||
|
{
|
||||||
|
return (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP];
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t dp8393x_crba(dp8393xState *s)
|
||||||
|
{
|
||||||
|
return (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0];
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t dp8393x_crda(dp8393xState *s)
|
||||||
|
{
|
||||||
|
return (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA];
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t dp8393x_rbwc(dp8393xState *s)
|
||||||
|
{
|
||||||
|
return (s->regs[SONIC_RBWC1] << 16) | s->regs[SONIC_RBWC0];
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t dp8393x_rrp(dp8393xState *s)
|
||||||
|
{
|
||||||
|
return (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_RRP];
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t dp8393x_tsa(dp8393xState *s)
|
||||||
|
{
|
||||||
|
return (s->regs[SONIC_TSA1] << 16) | s->regs[SONIC_TSA0];
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t dp8393x_ttda(dp8393xState *s)
|
||||||
|
{
|
||||||
|
return (s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA];
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t dp8393x_wt(dp8393xState *s)
|
||||||
|
{
|
||||||
|
return s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0];
|
||||||
|
}
|
||||||
|
|
||||||
static void dp8393x_update_irq(dp8393xState *s)
|
static void dp8393x_update_irq(dp8393xState *s)
|
||||||
{
|
{
|
||||||
int level = (s->regs[SONIC_IMR] & s->regs[SONIC_ISR]) ? 1 : 0;
|
int level = (s->regs[SONIC_IMR] & s->regs[SONIC_ISR]) ? 1 : 0;
|
||||||
@ -203,8 +249,7 @@ static void dp8393x_do_load_cam(dp8393xState *s)
|
|||||||
|
|
||||||
while (s->regs[SONIC_CDC] & 0x1f) {
|
while (s->regs[SONIC_CDC] & 0x1f) {
|
||||||
/* Fill current entry */
|
/* Fill current entry */
|
||||||
address_space_rw(&s->as,
|
address_space_rw(&s->as, dp8393x_cdp(s),
|
||||||
(s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP],
|
|
||||||
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
|
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
|
||||||
s->cam[index][0] = data[1 * width] & 0xff;
|
s->cam[index][0] = data[1 * width] & 0xff;
|
||||||
s->cam[index][1] = data[1 * width] >> 8;
|
s->cam[index][1] = data[1 * width] >> 8;
|
||||||
@ -222,8 +267,7 @@ static void dp8393x_do_load_cam(dp8393xState *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Read CAM enable */
|
/* Read CAM enable */
|
||||||
address_space_rw(&s->as,
|
address_space_rw(&s->as, dp8393x_cdp(s),
|
||||||
(s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP],
|
|
||||||
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
|
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
|
||||||
s->regs[SONIC_CE] = data[0 * width];
|
s->regs[SONIC_CE] = data[0 * width];
|
||||||
DPRINTF("load cam done. cam enable mask 0x%04x\n", s->regs[SONIC_CE]);
|
DPRINTF("load cam done. cam enable mask 0x%04x\n", s->regs[SONIC_CE]);
|
||||||
@ -242,8 +286,7 @@ static void dp8393x_do_read_rra(dp8393xState *s)
|
|||||||
/* Read memory */
|
/* Read memory */
|
||||||
width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
|
width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
|
||||||
size = sizeof(uint16_t) * 4 * width;
|
size = sizeof(uint16_t) * 4 * width;
|
||||||
address_space_rw(&s->as,
|
address_space_rw(&s->as, dp8393x_rrp(s),
|
||||||
(s->regs[SONIC_URRA] << 16) | s->regs[SONIC_RRP],
|
|
||||||
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
|
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
|
||||||
|
|
||||||
/* Update SONIC registers */
|
/* Update SONIC registers */
|
||||||
@ -292,7 +335,7 @@ static void dp8393x_set_next_tick(dp8393xState *s)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ticks = s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0];
|
ticks = dp8393x_wt(s);
|
||||||
s->wt_last_update = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
s->wt_last_update = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||||
delay = NANOSECONDS_PER_SECOND * ticks / 5000000;
|
delay = NANOSECONDS_PER_SECOND * ticks / 5000000;
|
||||||
timer_mod(s->watchdog, s->wt_last_update + delay);
|
timer_mod(s->watchdog, s->wt_last_update + delay);
|
||||||
@ -309,7 +352,7 @@ static void dp8393x_update_wt_regs(dp8393xState *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
elapsed = s->wt_last_update - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
elapsed = s->wt_last_update - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||||
val = s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0];
|
val = dp8393x_wt(s);
|
||||||
val -= elapsed / 5000000;
|
val -= elapsed / 5000000;
|
||||||
s->regs[SONIC_WT1] = (val >> 16) & 0xffff;
|
s->regs[SONIC_WT1] = (val >> 16) & 0xffff;
|
||||||
s->regs[SONIC_WT0] = (val >> 0) & 0xffff;
|
s->regs[SONIC_WT0] = (val >> 0) & 0xffff;
|
||||||
@ -356,12 +399,11 @@ static void dp8393x_do_transmit_packets(dp8393xState *s)
|
|||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
/* Read memory */
|
/* Read memory */
|
||||||
DPRINTF("Transmit packet at %08x\n",
|
|
||||||
(s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_CTDA]);
|
|
||||||
size = sizeof(uint16_t) * 6 * width;
|
size = sizeof(uint16_t) * 6 * width;
|
||||||
s->regs[SONIC_TTDA] = s->regs[SONIC_CTDA];
|
s->regs[SONIC_TTDA] = s->regs[SONIC_CTDA];
|
||||||
|
DPRINTF("Transmit packet at %08x\n", dp8393x_ttda(s));
|
||||||
address_space_rw(&s->as,
|
address_space_rw(&s->as,
|
||||||
((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * width,
|
dp8393x_ttda(s) + sizeof(uint16_t) * width,
|
||||||
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
|
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
|
||||||
tx_len = 0;
|
tx_len = 0;
|
||||||
|
|
||||||
@ -386,8 +428,7 @@ static void dp8393x_do_transmit_packets(dp8393xState *s)
|
|||||||
if (tx_len + len > sizeof(s->tx_buffer)) {
|
if (tx_len + len > sizeof(s->tx_buffer)) {
|
||||||
len = sizeof(s->tx_buffer) - tx_len;
|
len = sizeof(s->tx_buffer) - tx_len;
|
||||||
}
|
}
|
||||||
address_space_rw(&s->as,
|
address_space_rw(&s->as, dp8393x_tsa(s),
|
||||||
(s->regs[SONIC_TSA1] << 16) | s->regs[SONIC_TSA0],
|
|
||||||
MEMTXATTRS_UNSPECIFIED, &s->tx_buffer[tx_len], len, 0);
|
MEMTXATTRS_UNSPECIFIED, &s->tx_buffer[tx_len], len, 0);
|
||||||
tx_len += len;
|
tx_len += len;
|
||||||
|
|
||||||
@ -396,7 +437,7 @@ static void dp8393x_do_transmit_packets(dp8393xState *s)
|
|||||||
/* Read next fragment details */
|
/* Read next fragment details */
|
||||||
size = sizeof(uint16_t) * 3 * width;
|
size = sizeof(uint16_t) * 3 * width;
|
||||||
address_space_rw(&s->as,
|
address_space_rw(&s->as,
|
||||||
((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * i) * width,
|
dp8393x_ttda(s) + sizeof(uint16_t) * (4 + 3 * i) * width,
|
||||||
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
|
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
|
||||||
s->regs[SONIC_TSA0] = data[0 * width];
|
s->regs[SONIC_TSA0] = data[0 * width];
|
||||||
s->regs[SONIC_TSA1] = data[1 * width];
|
s->regs[SONIC_TSA1] = data[1 * width];
|
||||||
@ -430,14 +471,16 @@ static void dp8393x_do_transmit_packets(dp8393xState *s)
|
|||||||
data[0 * width] = s->regs[SONIC_TCR] & 0x0fff; /* status */
|
data[0 * width] = s->regs[SONIC_TCR] & 0x0fff; /* status */
|
||||||
size = sizeof(uint16_t) * width;
|
size = sizeof(uint16_t) * width;
|
||||||
address_space_rw(&s->as,
|
address_space_rw(&s->as,
|
||||||
(s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA],
|
dp8393x_ttda(s),
|
||||||
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 1);
|
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 1);
|
||||||
|
|
||||||
if (!(s->regs[SONIC_CR] & SONIC_CR_HTX)) {
|
if (!(s->regs[SONIC_CR] & SONIC_CR_HTX)) {
|
||||||
/* Read footer of packet */
|
/* Read footer of packet */
|
||||||
size = sizeof(uint16_t) * width;
|
size = sizeof(uint16_t) * width;
|
||||||
address_space_rw(&s->as,
|
address_space_rw(&s->as,
|
||||||
((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * s->regs[SONIC_TFC]) * width,
|
dp8393x_ttda(s) +
|
||||||
|
sizeof(uint16_t) *
|
||||||
|
(4 + 3 * s->regs[SONIC_TFC]) * width,
|
||||||
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
|
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
|
||||||
s->regs[SONIC_CTDA] = data[0 * width] & ~0x1;
|
s->regs[SONIC_CTDA] = data[0 * width] & ~0x1;
|
||||||
if (data[0 * width] & 0x1) {
|
if (data[0 * width] & 0x1) {
|
||||||
@ -700,7 +743,7 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
|
|||||||
if (s->regs[SONIC_LLFA] & 0x1) {
|
if (s->regs[SONIC_LLFA] & 0x1) {
|
||||||
/* Are we still in resource exhaustion? */
|
/* Are we still in resource exhaustion? */
|
||||||
size = sizeof(uint16_t) * 1 * width;
|
size = sizeof(uint16_t) * 1 * width;
|
||||||
address = ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width;
|
address = dp8393x_crda(s) + sizeof(uint16_t) * 5 * width;
|
||||||
address_space_rw(&s->as, address, MEMTXATTRS_UNSPECIFIED,
|
address_space_rw(&s->as, address, MEMTXATTRS_UNSPECIFIED,
|
||||||
(uint8_t *)data, size, 0);
|
(uint8_t *)data, size, 0);
|
||||||
if (data[0 * width] & 0x1) {
|
if (data[0 * width] & 0x1) {
|
||||||
@ -719,8 +762,8 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
|
|||||||
checksum = cpu_to_le32(crc32(0, buf, rx_len));
|
checksum = cpu_to_le32(crc32(0, buf, rx_len));
|
||||||
|
|
||||||
/* Put packet into RBA */
|
/* Put packet into RBA */
|
||||||
DPRINTF("Receive packet at %08x\n", (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0]);
|
DPRINTF("Receive packet at %08x\n", dp8393x_crba(s));
|
||||||
address = (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0];
|
address = dp8393x_crba(s);
|
||||||
address_space_rw(&s->as, address,
|
address_space_rw(&s->as, address,
|
||||||
MEMTXATTRS_UNSPECIFIED, (uint8_t *)buf, rx_len, 1);
|
MEMTXATTRS_UNSPECIFIED, (uint8_t *)buf, rx_len, 1);
|
||||||
address += rx_len;
|
address += rx_len;
|
||||||
@ -729,13 +772,13 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
|
|||||||
rx_len += 4;
|
rx_len += 4;
|
||||||
s->regs[SONIC_CRBA1] = address >> 16;
|
s->regs[SONIC_CRBA1] = address >> 16;
|
||||||
s->regs[SONIC_CRBA0] = address & 0xffff;
|
s->regs[SONIC_CRBA0] = address & 0xffff;
|
||||||
available = (s->regs[SONIC_RBWC1] << 16) | s->regs[SONIC_RBWC0];
|
available = dp8393x_rbwc(s);
|
||||||
available -= rx_len / 2;
|
available -= rx_len / 2;
|
||||||
s->regs[SONIC_RBWC1] = available >> 16;
|
s->regs[SONIC_RBWC1] = available >> 16;
|
||||||
s->regs[SONIC_RBWC0] = available & 0xffff;
|
s->regs[SONIC_RBWC0] = available & 0xffff;
|
||||||
|
|
||||||
/* Update status */
|
/* Update status */
|
||||||
if (((s->regs[SONIC_RBWC1] << 16) | s->regs[SONIC_RBWC0]) < s->regs[SONIC_EOBC]) {
|
if (dp8393x_rbwc(s) < s->regs[SONIC_EOBC]) {
|
||||||
s->regs[SONIC_RCR] |= SONIC_RCR_LPKT;
|
s->regs[SONIC_RCR] |= SONIC_RCR_LPKT;
|
||||||
}
|
}
|
||||||
s->regs[SONIC_RCR] |= packet_type;
|
s->regs[SONIC_RCR] |= packet_type;
|
||||||
@ -746,20 +789,19 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Write status to memory */
|
/* Write status to memory */
|
||||||
DPRINTF("Write status at %08x\n", (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]);
|
DPRINTF("Write status at %08x\n", dp8393x_crda(s));
|
||||||
data[0 * width] = s->regs[SONIC_RCR]; /* status */
|
data[0 * width] = s->regs[SONIC_RCR]; /* status */
|
||||||
data[1 * width] = rx_len; /* byte count */
|
data[1 * width] = rx_len; /* byte count */
|
||||||
data[2 * width] = s->regs[SONIC_TRBA0]; /* pkt_ptr0 */
|
data[2 * width] = s->regs[SONIC_TRBA0]; /* pkt_ptr0 */
|
||||||
data[3 * width] = s->regs[SONIC_TRBA1]; /* pkt_ptr1 */
|
data[3 * width] = s->regs[SONIC_TRBA1]; /* pkt_ptr1 */
|
||||||
data[4 * width] = s->regs[SONIC_RSC]; /* seq_no */
|
data[4 * width] = s->regs[SONIC_RSC]; /* seq_no */
|
||||||
size = sizeof(uint16_t) * 5 * width;
|
size = sizeof(uint16_t) * 5 * width;
|
||||||
address_space_rw(&s->as, (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA],
|
address_space_rw(&s->as, dp8393x_crda(s),
|
||||||
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 1);
|
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 1);
|
||||||
|
|
||||||
/* Move to next descriptor */
|
/* Move to next descriptor */
|
||||||
size = sizeof(uint16_t) * width;
|
size = sizeof(uint16_t) * width;
|
||||||
address_space_rw(&s->as,
|
address_space_rw(&s->as, dp8393x_crda(s) + sizeof(uint16_t) * 5 * width,
|
||||||
((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width,
|
|
||||||
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
|
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, size, 0);
|
||||||
s->regs[SONIC_LLFA] = data[0 * width];
|
s->regs[SONIC_LLFA] = data[0 * width];
|
||||||
if (s->regs[SONIC_LLFA] & 0x1) {
|
if (s->regs[SONIC_LLFA] & 0x1) {
|
||||||
@ -767,8 +809,7 @@ static ssize_t dp8393x_receive(NetClientState *nc, const uint8_t * buf,
|
|||||||
s->regs[SONIC_ISR] |= SONIC_ISR_RDE;
|
s->regs[SONIC_ISR] |= SONIC_ISR_RDE;
|
||||||
} else {
|
} else {
|
||||||
data[0 * width] = 0; /* in_use */
|
data[0 * width] = 0; /* in_use */
|
||||||
address_space_rw(&s->as,
|
address_space_rw(&s->as, dp8393x_crda(s) + sizeof(uint16_t) * 6 * width,
|
||||||
((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 6 * width,
|
|
||||||
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, sizeof(uint16_t), 1);
|
MEMTXATTRS_UNSPECIFIED, (uint8_t *)data, sizeof(uint16_t), 1);
|
||||||
s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA];
|
s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA];
|
||||||
s->regs[SONIC_ISR] |= SONIC_ISR_PKTRX;
|
s->regs[SONIC_ISR] |= SONIC_ISR_PKTRX;
|
||||||
|
@ -9,7 +9,9 @@
|
|||||||
#include "hw/hw.h"
|
#include "hw/hw.h"
|
||||||
#include "net/net.h"
|
#include "net/net.h"
|
||||||
#include "hw/m68k/mcf.h"
|
#include "hw/m68k/mcf.h"
|
||||||
|
#include "hw/m68k/mcf_fec.h"
|
||||||
#include "hw/net/mii.h"
|
#include "hw/net/mii.h"
|
||||||
|
#include "hw/sysbus.h"
|
||||||
/* For crc32 */
|
/* For crc32 */
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
#include "exec/address-spaces.h"
|
#include "exec/address-spaces.h"
|
||||||
@ -27,9 +29,10 @@ do { printf("mcf_fec: " fmt , ## __VA_ARGS__); } while (0)
|
|||||||
#define FEC_MAX_FRAME_SIZE 2032
|
#define FEC_MAX_FRAME_SIZE 2032
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
MemoryRegion *sysmem;
|
SysBusDevice parent_obj;
|
||||||
|
|
||||||
MemoryRegion iomem;
|
MemoryRegion iomem;
|
||||||
qemu_irq *irq;
|
qemu_irq irq[FEC_NUM_IRQ];
|
||||||
NICState *nic;
|
NICState *nic;
|
||||||
NICConf conf;
|
NICConf conf;
|
||||||
uint32_t irq_state;
|
uint32_t irq_state;
|
||||||
@ -68,7 +71,6 @@ typedef struct {
|
|||||||
#define FEC_RESET 1
|
#define FEC_RESET 1
|
||||||
|
|
||||||
/* Map interrupt flags onto IRQ lines. */
|
/* Map interrupt flags onto IRQ lines. */
|
||||||
#define FEC_NUM_IRQ 13
|
|
||||||
static const uint32_t mcf_fec_irq_map[FEC_NUM_IRQ] = {
|
static const uint32_t mcf_fec_irq_map[FEC_NUM_IRQ] = {
|
||||||
FEC_INT_TXF,
|
FEC_INT_TXF,
|
||||||
FEC_INT_TXB,
|
FEC_INT_TXB,
|
||||||
@ -208,8 +210,10 @@ static void mcf_fec_enable_rx(mcf_fec_state *s)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mcf_fec_reset(mcf_fec_state *s)
|
static void mcf_fec_reset(DeviceState *dev)
|
||||||
{
|
{
|
||||||
|
mcf_fec_state *s = MCF_FEC_NET(dev);
|
||||||
|
|
||||||
s->eir = 0;
|
s->eir = 0;
|
||||||
s->eimr = 0;
|
s->eimr = 0;
|
||||||
s->rx_enabled = 0;
|
s->rx_enabled = 0;
|
||||||
@ -330,7 +334,7 @@ static void mcf_fec_write(void *opaque, hwaddr addr,
|
|||||||
s->ecr = value;
|
s->ecr = value;
|
||||||
if (value & FEC_RESET) {
|
if (value & FEC_RESET) {
|
||||||
DPRINTF("Reset\n");
|
DPRINTF("Reset\n");
|
||||||
mcf_fec_reset(s);
|
mcf_fec_reset(opaque);
|
||||||
}
|
}
|
||||||
if ((s->ecr & FEC_EN) == 0) {
|
if ((s->ecr & FEC_EN) == 0) {
|
||||||
s->rx_enabled = 0;
|
s->rx_enabled = 0;
|
||||||
@ -513,24 +517,55 @@ static NetClientInfo net_mcf_fec_info = {
|
|||||||
.receive = mcf_fec_receive,
|
.receive = mcf_fec_receive,
|
||||||
};
|
};
|
||||||
|
|
||||||
void mcf_fec_init(MemoryRegion *sysmem, NICInfo *nd,
|
static void mcf_fec_realize(DeviceState *dev, Error **errp)
|
||||||
hwaddr base, qemu_irq *irq)
|
|
||||||
{
|
{
|
||||||
mcf_fec_state *s;
|
mcf_fec_state *s = MCF_FEC_NET(dev);
|
||||||
|
|
||||||
qemu_check_nic_model(nd, "mcf_fec");
|
|
||||||
|
|
||||||
s = (mcf_fec_state *)g_malloc0(sizeof(mcf_fec_state));
|
|
||||||
s->sysmem = sysmem;
|
|
||||||
s->irq = irq;
|
|
||||||
|
|
||||||
memory_region_init_io(&s->iomem, NULL, &mcf_fec_ops, s, "fec", 0x400);
|
|
||||||
memory_region_add_subregion(sysmem, base, &s->iomem);
|
|
||||||
|
|
||||||
s->conf.macaddr = nd->macaddr;
|
|
||||||
s->conf.peers.ncs[0] = nd->netdev;
|
|
||||||
|
|
||||||
s->nic = qemu_new_nic(&net_mcf_fec_info, &s->conf, nd->model, nd->name, s);
|
|
||||||
|
|
||||||
|
s->nic = qemu_new_nic(&net_mcf_fec_info, &s->conf,
|
||||||
|
object_get_typename(OBJECT(dev)), dev->id, s);
|
||||||
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
|
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void mcf_fec_instance_init(Object *obj)
|
||||||
|
{
|
||||||
|
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||||
|
mcf_fec_state *s = MCF_FEC_NET(obj);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
memory_region_init_io(&s->iomem, obj, &mcf_fec_ops, s, "fec", 0x400);
|
||||||
|
sysbus_init_mmio(sbd, &s->iomem);
|
||||||
|
for (i = 0; i < FEC_NUM_IRQ; i++) {
|
||||||
|
sysbus_init_irq(sbd, &s->irq[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Property mcf_fec_properties[] = {
|
||||||
|
DEFINE_NIC_PROPERTIES(mcf_fec_state, conf),
|
||||||
|
DEFINE_PROP_END_OF_LIST(),
|
||||||
|
};
|
||||||
|
|
||||||
|
static void mcf_fec_class_init(ObjectClass *oc, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(oc);
|
||||||
|
|
||||||
|
set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
|
||||||
|
dc->realize = mcf_fec_realize;
|
||||||
|
dc->desc = "MCF Fast Ethernet Controller network device";
|
||||||
|
dc->reset = mcf_fec_reset;
|
||||||
|
dc->props = mcf_fec_properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo mcf_fec_info = {
|
||||||
|
.name = TYPE_MCF_FEC_NET,
|
||||||
|
.parent = TYPE_SYS_BUS_DEVICE,
|
||||||
|
.instance_size = sizeof(mcf_fec_state),
|
||||||
|
.instance_init = mcf_fec_instance_init,
|
||||||
|
.class_init = mcf_fec_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void mcf_fec_register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&mcf_fec_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(mcf_fec_register_types)
|
||||||
|
@ -1779,7 +1779,6 @@ PCIDevice *pci_nic_init_nofail(NICInfo *nd, PCIBus *rootbus,
|
|||||||
const char *default_devaddr)
|
const char *default_devaddr)
|
||||||
{
|
{
|
||||||
const char *devaddr = nd->devaddr ? nd->devaddr : default_devaddr;
|
const char *devaddr = nd->devaddr ? nd->devaddr : default_devaddr;
|
||||||
Error *err = NULL;
|
|
||||||
PCIBus *bus;
|
PCIBus *bus;
|
||||||
PCIDevice *pci_dev;
|
PCIDevice *pci_dev;
|
||||||
DeviceState *dev;
|
DeviceState *dev;
|
||||||
@ -1805,13 +1804,7 @@ PCIDevice *pci_nic_init_nofail(NICInfo *nd, PCIBus *rootbus,
|
|||||||
pci_dev = pci_create(bus, devfn, pci_nic_names[i]);
|
pci_dev = pci_create(bus, devfn, pci_nic_names[i]);
|
||||||
dev = &pci_dev->qdev;
|
dev = &pci_dev->qdev;
|
||||||
qdev_set_nic_properties(dev, nd);
|
qdev_set_nic_properties(dev, nd);
|
||||||
|
qdev_init_nofail(dev);
|
||||||
object_property_set_bool(OBJECT(dev), true, "realized", &err);
|
|
||||||
if (err) {
|
|
||||||
error_report_err(err);
|
|
||||||
object_unparent(OBJECT(dev));
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return pci_dev;
|
return pci_dev;
|
||||||
}
|
}
|
||||||
|
@ -21,10 +21,6 @@ qemu_irq *mcf_intc_init(struct MemoryRegion *sysmem,
|
|||||||
hwaddr base,
|
hwaddr base,
|
||||||
M68kCPU *cpu);
|
M68kCPU *cpu);
|
||||||
|
|
||||||
/* mcf_fec.c */
|
|
||||||
void mcf_fec_init(struct MemoryRegion *sysmem, NICInfo *nd,
|
|
||||||
hwaddr base, qemu_irq *irq);
|
|
||||||
|
|
||||||
/* mcf5206.c */
|
/* mcf5206.c */
|
||||||
qemu_irq *mcf5206_init(struct MemoryRegion *sysmem,
|
qemu_irq *mcf5206_init(struct MemoryRegion *sysmem,
|
||||||
uint32_t base, M68kCPU *cpu);
|
uint32_t base, M68kCPU *cpu);
|
||||||
|
13
include/hw/m68k/mcf_fec.h
Normal file
13
include/hw/m68k/mcf_fec.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/*
|
||||||
|
* Definitions for the ColdFire Fast Ethernet Controller emulation.
|
||||||
|
*
|
||||||
|
* This code 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; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define TYPE_MCF_FEC_NET "mcf-fec"
|
||||||
|
#define MCF_FEC_NET(obj) OBJECT_CHECK(mcf_fec_state, (obj), TYPE_MCF_FEC_NET)
|
||||||
|
|
||||||
|
#define FEC_NUM_IRQ 13
|
@ -22,17 +22,22 @@
|
|||||||
|
|
||||||
uint32_t net_checksum_add_cont(int len, uint8_t *buf, int seq)
|
uint32_t net_checksum_add_cont(int len, uint8_t *buf, int seq)
|
||||||
{
|
{
|
||||||
uint32_t sum = 0;
|
uint32_t sum1 = 0, sum2 = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = seq; i < seq + len; i++) {
|
for (i = 0; i < len - 1; i += 2) {
|
||||||
if (i & 1) {
|
sum1 += (uint32_t)buf[i];
|
||||||
sum += (uint32_t)buf[i - seq];
|
sum2 += (uint32_t)buf[i + 1];
|
||||||
} else {
|
}
|
||||||
sum += (uint32_t)buf[i - seq] << 8;
|
if (i < len) {
|
||||||
}
|
sum1 += (uint32_t)buf[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seq & 1) {
|
||||||
|
return sum1 + (sum2 << 8);
|
||||||
|
} else {
|
||||||
|
return sum2 + (sum1 << 8);
|
||||||
}
|
}
|
||||||
return sum;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t net_checksum_finish(uint32_t sum)
|
uint16_t net_checksum_finish(uint32_t sum)
|
||||||
|
@ -789,8 +789,8 @@ int net_init_tap(const Netdev *netdev, const char *name,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
} else if (tap->has_fds) {
|
} else if (tap->has_fds) {
|
||||||
char **fds = g_new0(char *, MAX_TAP_QUEUES);
|
char **fds;
|
||||||
char **vhost_fds = g_new0(char *, MAX_TAP_QUEUES);
|
char **vhost_fds;
|
||||||
int nfds, nvhosts;
|
int nfds, nvhosts;
|
||||||
|
|
||||||
if (tap->has_ifname || tap->has_script || tap->has_downscript ||
|
if (tap->has_ifname || tap->has_script || tap->has_downscript ||
|
||||||
@ -802,6 +802,9 @@ int net_init_tap(const Netdev *netdev, const char *name,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fds = g_new0(char *, MAX_TAP_QUEUES);
|
||||||
|
vhost_fds = g_new0(char *, MAX_TAP_QUEUES);
|
||||||
|
|
||||||
nfds = get_fds(tap->fds, fds, MAX_TAP_QUEUES);
|
nfds = get_fds(tap->fds, fds, MAX_TAP_QUEUES);
|
||||||
if (tap->has_vhostfds) {
|
if (tap->has_vhostfds) {
|
||||||
nvhosts = get_fds(tap->vhostfds, vhost_fds, MAX_TAP_QUEUES);
|
nvhosts = get_fds(tap->vhostfds, vhost_fds, MAX_TAP_QUEUES);
|
||||||
|
Loading…
Reference in New Issue
Block a user