* GNU GPL, version 2 or (at your option) any later version.
*/
+#include "qemu/osdep.h"
#include "hw/sysbus.h"
#include "net/net.h"
#include "hw/devices.h"
#include "sysemu/sysemu.h"
#include "hw/ptimer.h"
+#include "qemu/log.h"
/* For crc32 */
#include <zlib.h>
#define CSR_E2P_CMD 0xb0
#define CSR_E2P_DATA 0xb4
+#define E2P_CMD_MAC_ADDR_LOADED 0x100
+
/* IRQ_CFG */
#define IRQ_INT 0x00001000
#define IRQ_EN 0x00000100
}
};
+#define TYPE_LAN9118 "lan9118"
+#define LAN9118(obj) OBJECT_CHECK(lan9118_state, (obj), TYPE_LAN9118)
+
typedef struct {
- SysBusDevice busdev;
+ SysBusDevice parent_obj;
+
NICState *nic;
NICConf conf;
qemu_irq irq;
{
int i;
if (s->eeprom[0] != 0xa5) {
- s->e2p_cmd &= ~0x10;
+ s->e2p_cmd &= ~E2P_CMD_MAC_ADDR_LOADED;
DPRINTF("MACADDR load failed\n");
return;
}
for (i = 0; i < 6; i++) {
s->conf.macaddr.a[i] = s->eeprom[i + 1];
}
- s->e2p_cmd |= 0x10;
+ s->e2p_cmd |= E2P_CMD_MAC_ADDR_LOADED;
DPRINTF("MACADDR loaded from eeprom\n");
lan9118_mac_changed(s);
}
static void lan9118_reset(DeviceState *d)
{
- lan9118_state *s = FROM_SYSBUS(lan9118_state, SYS_BUS_DEVICE(d));
+ lan9118_state *s = LAN9118(d);
+
s->irq_cfg &= (IRQ_TYPE | IRQ_POL);
s->int_sts = 0;
s->int_en = 0;
s->afc_cfg = 0;
s->e2p_cmd = 0;
s->e2p_data = 0;
- s->free_timer_start = qemu_get_clock_ns(vm_clock) / 40;
+ s->free_timer_start = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / 40;
ptimer_stop(s->timer);
ptimer_set_count(s->timer, 0xffff);
lan9118_reload_eeprom(s);
}
-static int lan9118_can_receive(NetClientState *nc)
-{
- return 1;
-}
-
static void rx_fifo_push(lan9118_state *s, uint32_t val)
{
int fifo_pos;
s->txp->cmd_a = val & 0x831f37ff;
s->txp->fifo_used++;
s->txp->state = TX_B;
+ s->txp->buffer_size = extract32(s->txp->cmd_a, 0, 11);
+ s->txp->offset = extract32(s->txp->cmd_a, 16, 5);
break;
case TX_B:
if (s->txp->cmd_a & 0x2000) {
/* First segment */
s->txp->cmd_b = val;
s->txp->fifo_used++;
- s->txp->buffer_size = s->txp->cmd_a & 0x7ff;
- s->txp->offset = (s->txp->cmd_a >> 16) & 0x1f;
/* End alignment does not include command words. */
n = (s->txp->buffer_size + s->txp->offset + 3) >> 2;
switch ((n >> 24) & 3) {
if (s->txp->buffer_size <= 0 && s->txp->pad != 0) {
s->txp->pad--;
} else {
- n = 4;
+ n = MIN(4, s->txp->buffer_size + s->txp->offset);
while (s->txp->offset) {
val >>= 8;
n--;
*/
break;
default:
- hw_error("lan9118: Unimplemented MAC register write: %d = 0x%x\n",
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "lan9118: Unimplemented MAC register write: %d = 0x%x\n",
s->mac_cmd & 0xf, val);
}
}
case MAC_FLOW:
return s->mac_flow;
default:
- hw_error("lan9118: Unimplemented MAC register read: %d\n",
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "lan9118: Unimplemented MAC register read: %d\n",
s->mac_cmd & 0xf);
+ return 0;
}
}
static void lan9118_eeprom_cmd(lan9118_state *s, int cmd, int addr)
{
- s->e2p_cmd = (s->e2p_cmd & 0x10) | (cmd << 28) | addr;
+ s->e2p_cmd = (s->e2p_cmd & E2P_CMD_MAC_ADDR_LOADED) | (cmd << 28) | addr;
switch (cmd) {
case 0:
s->e2p_data = s->eeprom[addr];
case CSR_HW_CFG:
if (val & 1) {
/* SRST */
- lan9118_reset(&s->busdev.qdev);
+ lan9118_reset(DEVICE(s));
} else {
s->hw_cfg = (val & 0x003f300) | (s->hw_cfg & 0x4);
}
break;
default:
- hw_error("lan9118_write: Bad reg 0x%x = %x\n", (int)offset, (int)val);
+ qemu_log_mask(LOG_GUEST_ERROR, "lan9118_write: Bad reg 0x%x = %x\n",
+ (int)offset, (int)val);
break;
}
lan9118_update(s);
case CSR_WORD_SWAP:
return s->word_swap;
case CSR_FREE_RUN:
- return (qemu_get_clock_ns(vm_clock) / 40) - s->free_timer_start;
+ return (qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) / 40) - s->free_timer_start;
case CSR_RX_DROP:
/* TODO: Implement dropped frames counter. */
return 0;
case CSR_E2P_DATA:
return s->e2p_data;
}
- hw_error("lan9118_read: Bad reg 0x%x\n", (int)offset);
+ qemu_log_mask(LOG_GUEST_ERROR, "lan9118_read: Bad reg 0x%x\n", (int)offset);
return 0;
}
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static void lan9118_cleanup(NetClientState *nc)
-{
- lan9118_state *s = qemu_get_nic_opaque(nc);
-
- s->nic = NULL;
-}
-
static NetClientInfo net_lan9118_info = {
- .type = NET_CLIENT_OPTIONS_KIND_NIC,
+ .type = NET_CLIENT_DRIVER_NIC,
.size = sizeof(NICState),
- .can_receive = lan9118_can_receive,
.receive = lan9118_receive,
- .cleanup = lan9118_cleanup,
.link_status_changed = lan9118_set_link,
};
-static int lan9118_init1(SysBusDevice *dev)
+static int lan9118_init1(SysBusDevice *sbd)
{
- lan9118_state *s = FROM_SYSBUS(lan9118_state, dev);
+ DeviceState *dev = DEVICE(sbd);
+ lan9118_state *s = LAN9118(dev);
QEMUBH *bh;
int i;
const MemoryRegionOps *mem_ops =
memory_region_init_io(&s->mmio, OBJECT(dev), mem_ops, s,
"lan9118-mmio", 0x100);
- sysbus_init_mmio(dev, &s->mmio);
- sysbus_init_irq(dev, &s->irq);
+ sysbus_init_mmio(sbd, &s->mmio);
+ sysbus_init_irq(sbd, &s->irq);
qemu_macaddr_default_if_unset(&s->conf.macaddr);
s->nic = qemu_new_nic(&net_lan9118_info, &s->conf,
- object_get_typename(OBJECT(dev)), dev->qdev.id, s);
+ object_get_typename(OBJECT(dev)), dev->id, s);
qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
s->eeprom[0] = 0xa5;
for (i = 0; i < 6; i++) {
s->txp = &s->tx_packet;
bh = qemu_bh_new(lan9118_tick, s);
- s->timer = ptimer_init(bh);
+ s->timer = ptimer_init(bh, PTIMER_POLICY_DEFAULT);
ptimer_set_freq(s->timer, 10000);
ptimer_set_limit(s->timer, 0xffff, 1);
}
static const TypeInfo lan9118_info = {
- .name = "lan9118",
+ .name = TYPE_LAN9118,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(lan9118_state),
.class_init = lan9118_class_init,
SysBusDevice *s;
qemu_check_nic_model(nd, "lan9118");
- dev = qdev_create(NULL, "lan9118");
+ dev = qdev_create(NULL, TYPE_LAN9118);
qdev_set_nic_properties(dev, nd);
qdev_init_nofail(dev);
s = SYS_BUS_DEVICE(dev);