* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#define DBGBIT(x) (1<<DEBUG_##x)
static int debugflags = DBGBIT(TXERR) | DBGBIT(GENERAL);
-#define DBGOUT(what, fmt, params...) do { \
+#define DBGOUT(what, fmt, ...) do { \
if (debugflags & DBGBIT(what)) \
- fprintf(stderr, "e1000: " fmt, ##params); \
+ fprintf(stderr, "e1000: " fmt, ## __VA_ARGS__); \
} while (0)
#else
-#define DBGOUT(what, fmt, params...) do {} while (0)
+#define DBGOUT(what, fmt, ...) do {} while (0)
#endif
#define IOPORT_SIZE 0x40
typedef struct E1000State_st {
PCIDevice dev;
VLANClientState *vc;
- NICInfo *nd;
- uint32_t mmio_base;
int mmio_index;
uint32_t mac_reg[0x8000];
if (val)
val |= E1000_ICR_INT_ASSERTED;
s->mac_reg[ICR] = val;
+ s->mac_reg[ICS] = val;
qemu_set_irq(s->dev.irq[0], (s->mac_reg[IMS] & s->mac_reg[ICR]) != 0);
}
return 2048;
}
+static void
+set_ctrl(E1000State *s, int index, uint32_t val)
+{
+ /* RST is self clearing */
+ s->mac_reg[CTRL] = val & ~E1000_CTRL_RST;
+}
+
static void
set_rx_control(E1000State *s, int index, uint32_t val)
{
}
if (!(val & E1000_EECD_CS)) { // rising, no CS (EEPROM reset)
memset(&s->eecd_state, 0, sizeof s->eecd_state);
+ /*
+ * restore old_eecd's E1000_EECD_SK (known to be on)
+ * to avoid false detection of a clock edge
+ */
+ s->eecd_state.old_eecd = E1000_EECD_SK;
return;
}
s->eecd_state.val_in <<= 1;
{
unsigned int index, r = s->mac_reg[EERD] & ~E1000_EEPROM_RW_REG_START;
+ if ((s->mac_reg[EERD] & E1000_EEPROM_RW_REG_START) == 0)
+ return (s->mac_reg[EERD]);
+
if ((index = r >> E1000_EEPROM_RW_ADDR_SHIFT) > EEPROM_CHECKSUM_REG)
- return 0;
- return (s->eeprom_data[index] << E1000_EEPROM_RW_REG_DATA) |
- E1000_EEPROM_RW_REG_DONE | r;
+ return (E1000_EEPROM_RW_REG_DONE | r);
+
+ return ((s->eeprom_data[index] << E1000_EEPROM_RW_REG_DATA) |
+ E1000_EEPROM_RW_REG_DONE | r);
}
static void
return 0;
}
+static void
+e1000_set_link_status(VLANClientState *vc)
+{
+ E1000State *s = vc->opaque;
+ uint32_t old_status = s->mac_reg[STATUS];
+
+ if (vc->link_down)
+ s->mac_reg[STATUS] &= ~E1000_STATUS_LU;
+ else
+ s->mac_reg[STATUS] |= E1000_STATUS_LU;
+
+ if (s->mac_reg[STATUS] != old_status)
+ set_ics(s, 0, E1000_ICR_LSC);
+}
+
static int
-e1000_can_receive(void *opaque)
+e1000_can_receive(VLANClientState *vc)
{
- E1000State *s = opaque;
+ E1000State *s = vc->opaque;
return (s->mac_reg[RCTL] & E1000_RCTL_EN);
}
-static void
-e1000_receive(void *opaque, const uint8_t *buf, int size)
+static ssize_t
+e1000_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
{
- E1000State *s = opaque;
+ E1000State *s = vc->opaque;
struct e1000_rx_desc desc;
target_phys_addr_t base;
unsigned int n, rdt;
uint8_t vlan_status = 0, vlan_offset = 0;
if (!(s->mac_reg[RCTL] & E1000_RCTL_EN))
- return;
+ return -1;
if (size > s->rxbuf_size) {
- DBGOUT(RX, "packet too large for buffers (%d > %d)\n", size,
- s->rxbuf_size);
- return;
+ DBGOUT(RX, "packet too large for buffers (%lu > %d)\n",
+ (unsigned long)size, s->rxbuf_size);
+ return -1;
}
if (!receive_filter(s, buf, size))
- return;
+ return size;
if (vlan_enabled(s) && is_vlan_packet(s, buf)) {
vlan_special = cpu_to_le16(be16_to_cpup((uint16_t *)(buf + 14)));
do {
if (s->mac_reg[RDH] == s->mac_reg[RDT] && s->check_rxov) {
set_ics(s, 0, E1000_ICS_RXO);
- return;
+ return -1;
}
base = ((uint64_t)s->mac_reg[RDBAH] << 32) + s->mac_reg[RDBAL] +
sizeof(desc) * s->mac_reg[RDH];
DBGOUT(RXERR, "RDH wraparound @%x, RDT %x, RDLEN %x\n",
rdh_start, s->mac_reg[RDT], s->mac_reg[RDLEN]);
set_ics(s, 0, E1000_ICS_RXO);
- return;
+ return -1;
}
} while (desc.buffer_addr == 0);
n = E1000_ICS_RXT0;
if ((rdt = s->mac_reg[RDT]) < s->mac_reg[RDH])
rdt += s->mac_reg[RDLEN] / sizeof(desc);
- if (((rdt - s->mac_reg[RDH]) * sizeof(desc)) << s->rxbuf_min_shift >=
- s->mac_reg[RDLEN])
+ if (((rdt - s->mac_reg[RDH]) * sizeof(desc)) <= s->mac_reg[RDLEN] >>
+ s->rxbuf_min_shift)
n |= E1000_ICS_RXDMT0;
set_ics(s, 0, n);
+
+ return size;
}
static uint32_t
getreg(WUFC), getreg(TDT), getreg(CTRL), getreg(LEDCTL),
getreg(MANC), getreg(MDIC), getreg(SWSM), getreg(STATUS),
getreg(TORL), getreg(TOTL), getreg(IMS), getreg(TCTL),
- getreg(RDH), getreg(RDT), getreg(VET),
+ getreg(RDH), getreg(RDT), getreg(VET), getreg(ICS),
[TOTH] = mac_read_clr8, [TORH] = mac_read_clr8, [GPRC] = mac_read_clr4,
[GPTC] = mac_read_clr4, [TPR] = mac_read_clr4, [TPT] = mac_read_clr4,
[MTA ... MTA+127] = &mac_readreg,
[VFTA ... VFTA+127] = &mac_readreg,
};
-enum { NREADOPS = sizeof(macreg_readops) / sizeof(*macreg_readops) };
+enum { NREADOPS = ARRAY_SIZE(macreg_readops) };
#define putreg(x) [x] = mac_writereg
static void (*macreg_writeops[])(E1000State *, int, uint32_t) = {
putreg(PBA), putreg(EERD), putreg(SWSM), putreg(WUFC),
putreg(TDBAL), putreg(TDBAH), putreg(TXDCTL), putreg(RDBAH),
- putreg(RDBAL), putreg(LEDCTL), putreg(CTRL), putreg(VET),
+ putreg(RDBAL), putreg(LEDCTL), putreg(VET),
[TDLEN] = set_dlen, [RDLEN] = set_dlen, [TCTL] = set_tctl,
[TDT] = set_tctl, [MDIC] = set_mdic, [ICS] = set_ics,
[TDH] = set_16bit, [RDH] = set_16bit, [RDT] = set_rdt,
[IMC] = set_imc, [IMS] = set_ims, [ICR] = set_icr,
- [EECD] = set_eecd, [RCTL] = set_rx_control,
+ [EECD] = set_eecd, [RCTL] = set_rx_control, [CTRL] = set_ctrl,
[RA ... RA+31] = &mac_writereg,
[MTA ... MTA+127] = &mac_writereg,
[VFTA ... VFTA+127] = &mac_writereg,
};
-enum { NWRITEOPS = sizeof(macreg_writeops) / sizeof(*macreg_writeops) };
+enum { NWRITEOPS = ARRAY_SIZE(macreg_writeops) };
static void
e1000_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
E1000State *s = opaque;
- unsigned int index = ((addr - s->mmio_base) & 0x1ffff) >> 2;
+ unsigned int index = (addr & 0x1ffff) >> 2;
#ifdef TARGET_WORDS_BIGENDIAN
val = bswap32(val);
e1000_mmio_readl(void *opaque, target_phys_addr_t addr)
{
E1000State *s = opaque;
- unsigned int index = ((addr - s->mmio_base) & 0x1ffff) >> 2;
+ unsigned int index = (addr & 0x1ffff) >> 2;
if (index < NREADOPS && macreg_readops[index])
{
TDT, TORH, TORL, TOTH, TOTL, TPR, TPT, TXDCTL, WUFC,
VET,
};
-enum { MAC_NSAVE = sizeof mac_regtosave/sizeof *mac_regtosave };
+enum { MAC_NSAVE = ARRAY_SIZE(mac_regtosave) };
static const struct {
int size;
int array0;
} mac_regarraystosave[] = { {32, RA}, {128, MTA}, {128, VFTA} };
-enum { MAC_NARRAYS = sizeof mac_regarraystosave/sizeof *mac_regarraystosave };
+enum { MAC_NARRAYS = ARRAY_SIZE(mac_regarraystosave) };
static void
nic_save(QEMUFile *f, void *opaque)
{
- E1000State *s = (E1000State *)opaque;
+ E1000State *s = opaque;
int i, j;
pci_device_save(&s->dev, f);
- qemu_put_be32s(f, &s->mmio_base);
+ qemu_put_be32(f, 0);
qemu_put_be32s(f, &s->rxbuf_size);
qemu_put_be32s(f, &s->rxbuf_min_shift);
qemu_put_be32s(f, &s->eecd_state.val_in);
static int
nic_load(QEMUFile *f, void *opaque, int version_id)
{
- E1000State *s = (E1000State *)opaque;
+ E1000State *s = opaque;
int i, j, ret;
if ((ret = pci_device_load(&s->dev, f)) < 0)
return ret;
if (version_id == 1)
qemu_get_sbe32s(f, &i); /* once some unused instance id */
- qemu_get_be32s(f, &s->mmio_base);
+ qemu_get_be32(f); /* Ignored. Was mmio_base. */
qemu_get_be32s(f, &s->rxbuf_size);
qemu_get_be32s(f, &s->rxbuf_min_shift);
qemu_get_be32s(f, &s->eecd_state.val_in);
/* PCI interface */
-static CPUWriteMemoryFunc *e1000_mmio_write[] = {
+static CPUWriteMemoryFunc * const e1000_mmio_write[] = {
e1000_mmio_writeb, e1000_mmio_writew, e1000_mmio_writel
};
-static CPUReadMemoryFunc *e1000_mmio_read[] = {
+static CPUReadMemoryFunc * const e1000_mmio_read[] = {
e1000_mmio_readb, e1000_mmio_readw, e1000_mmio_readl
};
e1000_mmio_map(PCIDevice *pci_dev, int region_num,
uint32_t addr, uint32_t size, int type)
{
- E1000State *d = (E1000State *)pci_dev;
+ E1000State *d = DO_UPCAST(E1000State, dev, pci_dev);
+ int i;
+ const uint32_t excluded_regs[] = {
+ E1000_MDIC, E1000_ICR, E1000_ICS, E1000_IMS,
+ E1000_IMC, E1000_TCTL, E1000_TDT, PNPMMIO_SIZE
+ };
+
DBGOUT(MMIO, "e1000_mmio_map addr=0x%08x 0x%08x\n", addr, size);
- d->mmio_base = addr;
cpu_register_physical_memory(addr, PNPMMIO_SIZE, d->mmio_index);
+ qemu_register_coalesced_mmio(addr, excluded_regs[0]);
+
+ for (i = 0; excluded_regs[i] != PNPMMIO_SIZE; i++)
+ qemu_register_coalesced_mmio(addr + excluded_regs[i] + 4,
+ excluded_regs[i + 1] -
+ excluded_regs[i] - 4);
}
-void
-pci_e1000_init(PCIBus *bus, NICInfo *nd, int devfn)
+static void
+e1000_cleanup(VLANClientState *vc)
{
- E1000State *d;
+ E1000State *d = vc->opaque;
+
+ unregister_savevm("e1000", d);
+}
+
+static int
+pci_e1000_uninit(PCIDevice *dev)
+{
+ E1000State *d = DO_UPCAST(E1000State, dev, dev);
+
+ cpu_unregister_io_memory(d->mmio_index);
+
+ return 0;
+}
+
+static void e1000_reset(void *opaque)
+{
+ E1000State *d = opaque;
+
+ memset(d->phy_reg, 0, sizeof d->phy_reg);
+ memmove(d->phy_reg, phy_reg_init, sizeof phy_reg_init);
+ memset(d->mac_reg, 0, sizeof d->mac_reg);
+ memmove(d->mac_reg, mac_reg_init, sizeof mac_reg_init);
+ d->rxbuf_min_shift = 1;
+ memset(&d->tx, 0, sizeof d->tx);
+}
+
+static int pci_e1000_init(PCIDevice *pci_dev)
+{
+ E1000State *d = DO_UPCAST(E1000State, dev, pci_dev);
uint8_t *pci_conf;
uint16_t checksum = 0;
static const char info_str[] = "e1000";
int i;
-
- d = (E1000State *)pci_register_device(bus, "e1000",
- sizeof(E1000State), devfn, NULL, NULL);
+ uint8_t macaddr[6];
pci_conf = d->dev.config;
- memset(pci_conf, 0, 256);
- *(uint16_t *)(pci_conf+0x00) = cpu_to_le16(0x8086);
- *(uint16_t *)(pci_conf+0x02) = cpu_to_le16(E1000_DEVID);
+ pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL);
+ pci_config_set_device_id(pci_conf, E1000_DEVID);
*(uint16_t *)(pci_conf+0x04) = cpu_to_le16(0x0407);
*(uint16_t *)(pci_conf+0x06) = cpu_to_le16(0x0010);
pci_conf[0x08] = 0x03;
- pci_conf[0x0a] = 0x00; // ethernet network controller
- pci_conf[0x0b] = 0x02;
+ pci_config_set_class(pci_conf, PCI_CLASS_NETWORK_ETHERNET);
pci_conf[0x0c] = 0x10;
pci_conf[0x3d] = 1; // interrupt pin 0
- d->mmio_index = cpu_register_io_memory(0, e1000_mmio_read,
+ d->mmio_index = cpu_register_io_memory(e1000_mmio_read,
e1000_mmio_write, d);
- pci_register_io_region((PCIDevice *)d, 0, PNPMMIO_SIZE,
+ pci_register_bar((PCIDevice *)d, 0, PNPMMIO_SIZE,
PCI_ADDRESS_SPACE_MEM, e1000_mmio_map);
- pci_register_io_region((PCIDevice *)d, 1, IOPORT_SIZE,
+ pci_register_bar((PCIDevice *)d, 1, IOPORT_SIZE,
PCI_ADDRESS_SPACE_IO, ioport_map);
- d->nd = nd;
memmove(d->eeprom_data, e1000_eeprom_template,
sizeof e1000_eeprom_template);
+ qdev_get_macaddr(&d->dev.qdev, macaddr);
for (i = 0; i < 3; i++)
- d->eeprom_data[i] = (nd->macaddr[2*i+1]<<8) | nd->macaddr[2*i];
+ d->eeprom_data[i] = (macaddr[2*i+1]<<8) | macaddr[2*i];
for (i = 0; i < EEPROM_CHECKSUM_REG; i++)
checksum += d->eeprom_data[i];
checksum = (uint16_t) EEPROM_SUM - checksum;
d->eeprom_data[EEPROM_CHECKSUM_REG] = checksum;
- memset(d->phy_reg, 0, sizeof d->phy_reg);
- memmove(d->phy_reg, phy_reg_init, sizeof phy_reg_init);
- memset(d->mac_reg, 0, sizeof d->mac_reg);
- memmove(d->mac_reg, mac_reg_init, sizeof mac_reg_init);
- d->rxbuf_min_shift = 1;
- memset(&d->tx, 0, sizeof d->tx);
-
- d->vc = qemu_new_vlan_client(nd->vlan, e1000_receive,
- e1000_can_receive, d);
+ d->vc = qdev_get_vlan_client(&d->dev.qdev,
+ e1000_can_receive, e1000_receive,
+ NULL, e1000_cleanup, d);
+ d->vc->link_status_changed = e1000_set_link_status;
- snprintf(d->vc->info_str, sizeof(d->vc->info_str),
- "%s macaddr=%02x:%02x:%02x:%02x:%02x:%02x", info_str,
- d->nd->macaddr[0], d->nd->macaddr[1], d->nd->macaddr[2],
- d->nd->macaddr[3], d->nd->macaddr[4], d->nd->macaddr[5]);
+ qemu_format_nic_info_str(d->vc, macaddr);
register_savevm(info_str, -1, 2, nic_save, nic_load, d);
+ d->dev.unregister = pci_e1000_uninit;
+ qemu_register_reset(e1000_reset, d);
+ e1000_reset(d);
+ return 0;
+}
+
+static PCIDeviceInfo e1000_info = {
+ .qdev.name = "e1000",
+ .qdev.size = sizeof(E1000State),
+ .init = pci_e1000_init,
+};
+
+static void e1000_register_devices(void)
+{
+ pci_qdev_register(&e1000_info);
}
+
+device_init(e1000_register_devices)