mirror of https://gitee.com/openkylin/qemu.git
virtio,make,pci,e1000,vfio,piix
This includes my timestamp generation cleanup, Amos's and my work on virtio net commands, pci,e1000,vfio and piix fixes. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.13 (GNU/Linux) iQEcBAABAgAGBQJRCmGLAAoJECgfDbjSjVRp6PUH/1YsrRgrPUEhrhHwM4OPAMB5 D/kcTwrS4R7XNk6HRElfVnPbDYl2iIqi7a6RrY/x2jQvMBaghT5v6w07kg9gCooF qNpHUr0y2YHy9yIFpG36SntqDmXXqvd4ngAMn7EviDH6OvwI8dSqbIVRUFc8yw5c g+EyEQpyZieBVEGnWPEl6qDo4KFw9nU3p0A93fsQnKikXet00d+V01hQ4TALbBxk EkeM1tYTjVlHOZAPsq6I2/CvRCO7YbIaboJJ9ZQ83GCX7TEsYELaMOc1qxVOAv0k rKVijwqyHvhncxumPM/NIUuSnQTQxxeJmV4mWLARPGSh7FYorqMesnY4p1aX4RQ= =k7PQ -----END PGP SIGNATURE----- Merge remote-tracking branch 'mst/tags/for_anthony' into staging virtio,make,pci,e1000,vfio,piix This includes my timestamp generation cleanup, Amos's and my work on virtio net commands, pci,e1000,vfio and piix fixes. Signed-off-by: Michael S. Tsirkin <mst@redhat.com> # gpg: Signature made Thu 31 Jan 2013 06:20:27 AM CST using RSA key ID D28D5469 # gpg: Can't check signature: public key not found # By Michael S. Tsirkin (6) and others # Via Michael S. Tsirkin * mst/tags/for_anthony: vfio-pci: Enable PCIe extended config space PIIX3: reset the VM when the Reset Control Register's RCPU bit gets set ich9: add support for pci assignment virtio-net: rename ctrl rx commands virtio-net: introduce a new macaddr control virtio-net: remove layout assumptions for ctrl vq virtio-net: revert mac on reset rules/mak: make clean should blow away timestamp files Makefile: clean timestamp generation rule rules.mak: cleanup config generation rules e1000: document ICS read behaviour
This commit is contained in:
commit
c628d74738
10
hw/e1000.c
10
hw/e1000.c
|
@ -237,7 +237,17 @@ set_interrupt_cause(E1000State *s, int index, uint32_t val)
|
|||
val |= E1000_ICR_INT_ASSERTED;
|
||||
}
|
||||
s->mac_reg[ICR] = val;
|
||||
|
||||
/*
|
||||
* Make sure ICR and ICS registers have the same value.
|
||||
* The spec says that the ICS register is write-only. However in practice,
|
||||
* on real hardware ICS is readable, and for reads it has the same value as
|
||||
* ICR (except that ICS does not have the clear on read behaviour of ICR).
|
||||
*
|
||||
* The VxWorks PRO/1000 driver uses this behaviour.
|
||||
*/
|
||||
s->mac_reg[ICS] = val;
|
||||
|
||||
qemu_set_irq(s->dev.irq[0], (s->mac_reg[IMS] & s->mac_reg[ICR]) != 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
void ich9_lpc_set_irq(void *opaque, int irq_num, int level);
|
||||
int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx);
|
||||
PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin);
|
||||
void ich9_lpc_pm_init(PCIDevice *pci_lpc, qemu_irq cmos_s3);
|
||||
PCIBus *ich9_d2pbr_init(PCIBus *bus, int devfn, int sec_bus);
|
||||
i2c_bus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base);
|
||||
|
|
|
@ -158,6 +158,7 @@ static void ich9_cc_write(void *opaque, hwaddr addr,
|
|||
|
||||
ich9_cc_addr_len(&addr, &len);
|
||||
memcpy(lpc->chip_config + addr, &val, len);
|
||||
pci_bus_fire_intx_routing_notifier(lpc->d.bus);
|
||||
ich9_cc_update(lpc);
|
||||
}
|
||||
|
||||
|
@ -286,6 +287,32 @@ int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx)
|
|||
return lpc->irr[PCI_SLOT(pci_dev->devfn)][intx];
|
||||
}
|
||||
|
||||
PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin)
|
||||
{
|
||||
ICH9LPCState *lpc = opaque;
|
||||
PCIINTxRoute route;
|
||||
int pic_irq;
|
||||
int pic_dis;
|
||||
|
||||
assert(0 <= pirq_pin);
|
||||
assert(pirq_pin < ICH9_LPC_NB_PIRQS);
|
||||
|
||||
route.mode = PCI_INTX_ENABLED;
|
||||
ich9_lpc_pic_irq(lpc, pirq_pin, &pic_irq, &pic_dis);
|
||||
if (!pic_dis) {
|
||||
if (pic_irq < ICH9_LPC_PIC_NUM_PINS) {
|
||||
route.irq = pic_irq;
|
||||
} else {
|
||||
route.mode = PCI_INTX_DISABLED;
|
||||
route.irq = -1;
|
||||
}
|
||||
} else {
|
||||
route.irq = ich9_pirq_to_gsi(pirq_pin);
|
||||
}
|
||||
|
||||
return route;
|
||||
}
|
||||
|
||||
static int ich9_lpc_sci_irq(ICH9LPCState *lpc)
|
||||
{
|
||||
switch (lpc->d.config[ICH9_LPC_ACPI_CTRL] &
|
||||
|
@ -405,6 +432,12 @@ static void ich9_lpc_config_write(PCIDevice *d,
|
|||
if (ranges_overlap(addr, len, ICH9_LPC_RCBA, 4)) {
|
||||
ich9_lpc_rcba_update(lpc, rbca_old);
|
||||
}
|
||||
if (ranges_overlap(addr, len, ICH9_LPC_PIRQA_ROUT, 4)) {
|
||||
pci_bus_fire_intx_routing_notifier(lpc->d.bus);
|
||||
}
|
||||
if (ranges_overlap(addr, len, ICH9_LPC_PIRQE_ROUT, 4)) {
|
||||
pci_bus_fire_intx_routing_notifier(lpc->d.bus);
|
||||
}
|
||||
}
|
||||
|
||||
static void ich9_lpc_reset(DeviceState *qdev)
|
||||
|
|
|
@ -309,6 +309,10 @@ static QEMUMachine pc_i440fx_machine_v1_4 = {
|
|||
.driver = "usb-tablet",\
|
||||
.property = "usb_version",\
|
||||
.value = stringify(1),\
|
||||
},{\
|
||||
.driver = "virtio-net-pci",\
|
||||
.property = "ctrl_mac_addr",\
|
||||
.value = "off", \
|
||||
}
|
||||
|
||||
static QEMUMachine pc_machine_v1_3 = {
|
||||
|
|
|
@ -147,6 +147,7 @@ static void pc_q35_init(QEMUMachineInitArgs *args)
|
|||
ich9_lpc->ioapic = gsi_state->ioapic_irq;
|
||||
pci_bus_irqs(host_bus, ich9_lpc_set_irq, ich9_lpc_map_irq, ich9_lpc,
|
||||
ICH9_LPC_NB_PIRQS);
|
||||
pci_bus_set_route_irq_fn(host_bus, ich9_route_intx_pin_to_irq);
|
||||
isa_bus = ich9_lpc->isa_bus;
|
||||
|
||||
/*end early*/
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "qemu/range.h"
|
||||
#include "xen.h"
|
||||
#include "pam.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
|
||||
/*
|
||||
* I440FX chipset data sheet.
|
||||
|
@ -46,6 +47,12 @@ typedef struct I440FXState {
|
|||
#define XEN_PIIX_NUM_PIRQS 128ULL
|
||||
#define PIIX_PIRQC 0x60
|
||||
|
||||
/*
|
||||
* Reset Control Register: PCI-accessible ISA-Compatible Register at address
|
||||
* 0xcf9, provided by the PCI/ISA bridge (PIIX3 PCI function 0, 8086:7000).
|
||||
*/
|
||||
#define RCR_IOPORT 0xcf9
|
||||
|
||||
typedef struct PIIX3State {
|
||||
PCIDevice dev;
|
||||
|
||||
|
@ -67,6 +74,12 @@ typedef struct PIIX3State {
|
|||
|
||||
/* This member isn't used. Just for save/load compatibility */
|
||||
int32_t pci_irq_levels_vmstate[PIIX_NUM_PIRQS];
|
||||
|
||||
/* Reset Control Register contents */
|
||||
uint8_t rcr;
|
||||
|
||||
/* IO memory region for Reset Control Register (RCR_IOPORT) */
|
||||
MemoryRegion rcr_mem;
|
||||
} PIIX3State;
|
||||
|
||||
struct PCII440FXState {
|
||||
|
@ -442,6 +455,7 @@ static void piix3_reset(void *opaque)
|
|||
pci_conf[0xae] = 0x00;
|
||||
|
||||
d->pic_levels = 0;
|
||||
d->rcr = 0;
|
||||
}
|
||||
|
||||
static int piix3_post_load(void *opaque, int version_id)
|
||||
|
@ -462,6 +476,23 @@ static void piix3_pre_save(void *opaque)
|
|||
}
|
||||
}
|
||||
|
||||
static bool piix3_rcr_needed(void *opaque)
|
||||
{
|
||||
PIIX3State *piix3 = opaque;
|
||||
|
||||
return (piix3->rcr != 0);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_piix3_rcr = {
|
||||
.name = "PIIX3/rcr",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField []) {
|
||||
VMSTATE_UINT8(rcr, PIIX3State),
|
||||
VMSTATE_END_OF_LIST()
|
||||
}
|
||||
};
|
||||
|
||||
static const VMStateDescription vmstate_piix3 = {
|
||||
.name = "PIIX3",
|
||||
.version_id = 3,
|
||||
|
@ -469,19 +500,56 @@ static const VMStateDescription vmstate_piix3 = {
|
|||
.minimum_version_id_old = 2,
|
||||
.post_load = piix3_post_load,
|
||||
.pre_save = piix3_pre_save,
|
||||
.fields = (VMStateField []) {
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_PCI_DEVICE(dev, PIIX3State),
|
||||
VMSTATE_INT32_ARRAY_V(pci_irq_levels_vmstate, PIIX3State,
|
||||
PIIX_NUM_PIRQS, 3),
|
||||
VMSTATE_END_OF_LIST()
|
||||
},
|
||||
.subsections = (VMStateSubsection[]) {
|
||||
{
|
||||
.vmsd = &vmstate_piix3_rcr,
|
||||
.needed = piix3_rcr_needed,
|
||||
},
|
||||
{ 0 }
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static void rcr_write(void *opaque, hwaddr addr, uint64_t val, unsigned len)
|
||||
{
|
||||
PIIX3State *d = opaque;
|
||||
|
||||
if (val & 4) {
|
||||
qemu_system_reset_request();
|
||||
return;
|
||||
}
|
||||
d->rcr = val & 2; /* keep System Reset type only */
|
||||
}
|
||||
|
||||
static uint64_t rcr_read(void *opaque, hwaddr addr, unsigned len)
|
||||
{
|
||||
PIIX3State *d = opaque;
|
||||
|
||||
return d->rcr;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps rcr_ops = {
|
||||
.read = rcr_read,
|
||||
.write = rcr_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN
|
||||
};
|
||||
|
||||
static int piix3_initfn(PCIDevice *dev)
|
||||
{
|
||||
PIIX3State *d = DO_UPCAST(PIIX3State, dev, dev);
|
||||
|
||||
isa_bus_new(&d->dev.qdev, pci_address_space_io(dev));
|
||||
|
||||
memory_region_init_io(&d->rcr_mem, &rcr_ops, d, "piix3-reset-control", 1);
|
||||
memory_region_add_subregion_overlap(pci_address_space_io(dev), RCR_IOPORT,
|
||||
&d->rcr_mem, 1);
|
||||
|
||||
qemu_register_reset(piix3_reset, d);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1899,6 +1899,9 @@ static int vfio_get_device(VFIOGroup *group, const char *name, VFIODevice *vdev)
|
|||
(unsigned long)reg_info.flags);
|
||||
|
||||
vdev->config_size = reg_info.size;
|
||||
if (vdev->config_size == PCI_CONFIG_SPACE_SIZE) {
|
||||
vdev->pdev.cap_present &= ~QEMU_PCI_CAP_EXPRESS;
|
||||
}
|
||||
vdev->config_offset = reg_info.offset;
|
||||
|
||||
error:
|
||||
|
@ -2121,6 +2124,7 @@ static void vfio_pci_dev_class_init(ObjectClass *klass, void *data)
|
|||
pdc->exit = vfio_exitfn;
|
||||
pdc->config_read = vfio_pci_read_config;
|
||||
pdc->config_write = vfio_pci_write_config;
|
||||
pdc->is_express = 1; /* We might be */
|
||||
}
|
||||
|
||||
static const TypeInfo vfio_pci_dev_info = {
|
||||
|
|
147
hw/virtio-net.c
147
hw/virtio-net.c
|
@ -93,7 +93,8 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config)
|
|||
|
||||
memcpy(&netcfg, config, sizeof(netcfg));
|
||||
|
||||
if (memcmp(netcfg.mac, n->mac, ETH_ALEN)) {
|
||||
if (!(n->vdev.guest_features >> VIRTIO_NET_F_CTRL_MAC_ADDR & 1) &&
|
||||
memcmp(netcfg.mac, n->mac, ETH_ALEN)) {
|
||||
memcpy(n->mac, netcfg.mac, ETH_ALEN);
|
||||
qemu_format_nic_info_str(&n->nic->nc, n->mac);
|
||||
}
|
||||
|
@ -199,6 +200,7 @@ static void virtio_net_reset(VirtIODevice *vdev)
|
|||
n->mac_table.multi_overflow = 0;
|
||||
n->mac_table.uni_overflow = 0;
|
||||
memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN);
|
||||
memcpy(&n->mac[0], &n->nic->conf->macaddr, sizeof(n->mac));
|
||||
memset(n->vlans, 0, MAX_VLAN >> 3);
|
||||
}
|
||||
|
||||
|
@ -315,44 +317,54 @@ static void virtio_net_set_features(VirtIODevice *vdev, uint32_t features)
|
|||
}
|
||||
|
||||
static int virtio_net_handle_rx_mode(VirtIONet *n, uint8_t cmd,
|
||||
VirtQueueElement *elem)
|
||||
struct iovec *iov, unsigned int iov_cnt)
|
||||
{
|
||||
uint8_t on;
|
||||
size_t s;
|
||||
|
||||
if (elem->out_num != 2 || elem->out_sg[1].iov_len != sizeof(on)) {
|
||||
error_report("virtio-net ctrl invalid rx mode command");
|
||||
exit(1);
|
||||
s = iov_to_buf(iov, iov_cnt, 0, &on, sizeof(on));
|
||||
if (s != sizeof(on)) {
|
||||
return VIRTIO_NET_ERR;
|
||||
}
|
||||
|
||||
on = ldub_p(elem->out_sg[1].iov_base);
|
||||
|
||||
if (cmd == VIRTIO_NET_CTRL_RX_MODE_PROMISC)
|
||||
if (cmd == VIRTIO_NET_CTRL_RX_PROMISC) {
|
||||
n->promisc = on;
|
||||
else if (cmd == VIRTIO_NET_CTRL_RX_MODE_ALLMULTI)
|
||||
} else if (cmd == VIRTIO_NET_CTRL_RX_ALLMULTI) {
|
||||
n->allmulti = on;
|
||||
else if (cmd == VIRTIO_NET_CTRL_RX_MODE_ALLUNI)
|
||||
} else if (cmd == VIRTIO_NET_CTRL_RX_ALLUNI) {
|
||||
n->alluni = on;
|
||||
else if (cmd == VIRTIO_NET_CTRL_RX_MODE_NOMULTI)
|
||||
} else if (cmd == VIRTIO_NET_CTRL_RX_NOMULTI) {
|
||||
n->nomulti = on;
|
||||
else if (cmd == VIRTIO_NET_CTRL_RX_MODE_NOUNI)
|
||||
} else if (cmd == VIRTIO_NET_CTRL_RX_NOUNI) {
|
||||
n->nouni = on;
|
||||
else if (cmd == VIRTIO_NET_CTRL_RX_MODE_NOBCAST)
|
||||
} else if (cmd == VIRTIO_NET_CTRL_RX_NOBCAST) {
|
||||
n->nobcast = on;
|
||||
else
|
||||
} else {
|
||||
return VIRTIO_NET_ERR;
|
||||
}
|
||||
|
||||
return VIRTIO_NET_OK;
|
||||
}
|
||||
|
||||
static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
|
||||
VirtQueueElement *elem)
|
||||
struct iovec *iov, unsigned int iov_cnt)
|
||||
{
|
||||
struct virtio_net_ctrl_mac mac_data;
|
||||
size_t s;
|
||||
|
||||
if (cmd != VIRTIO_NET_CTRL_MAC_TABLE_SET || elem->out_num != 3 ||
|
||||
elem->out_sg[1].iov_len < sizeof(mac_data) ||
|
||||
elem->out_sg[2].iov_len < sizeof(mac_data))
|
||||
if (cmd == VIRTIO_NET_CTRL_MAC_ADDR_SET) {
|
||||
if (iov_size(iov, iov_cnt) != sizeof(n->mac)) {
|
||||
return VIRTIO_NET_ERR;
|
||||
}
|
||||
s = iov_to_buf(iov, iov_cnt, 0, &n->mac, sizeof(n->mac));
|
||||
assert(s == sizeof(n->mac));
|
||||
qemu_format_nic_info_str(&n->nic->nc, n->mac);
|
||||
return VIRTIO_NET_OK;
|
||||
}
|
||||
|
||||
if (cmd != VIRTIO_NET_CTRL_MAC_TABLE_SET) {
|
||||
return VIRTIO_NET_ERR;
|
||||
}
|
||||
|
||||
n->mac_table.in_use = 0;
|
||||
n->mac_table.first_multi = 0;
|
||||
|
@ -360,54 +372,72 @@ static int virtio_net_handle_mac(VirtIONet *n, uint8_t cmd,
|
|||
n->mac_table.multi_overflow = 0;
|
||||
memset(n->mac_table.macs, 0, MAC_TABLE_ENTRIES * ETH_ALEN);
|
||||
|
||||
mac_data.entries = ldl_p(elem->out_sg[1].iov_base);
|
||||
|
||||
if (sizeof(mac_data.entries) +
|
||||
(mac_data.entries * ETH_ALEN) > elem->out_sg[1].iov_len)
|
||||
s = iov_to_buf(iov, iov_cnt, 0, &mac_data.entries,
|
||||
sizeof(mac_data.entries));
|
||||
mac_data.entries = ldl_p(&mac_data.entries);
|
||||
if (s != sizeof(mac_data.entries)) {
|
||||
return VIRTIO_NET_ERR;
|
||||
}
|
||||
iov_discard_front(&iov, &iov_cnt, s);
|
||||
|
||||
if (mac_data.entries * ETH_ALEN > iov_size(iov, iov_cnt)) {
|
||||
return VIRTIO_NET_ERR;
|
||||
}
|
||||
|
||||
if (mac_data.entries <= MAC_TABLE_ENTRIES) {
|
||||
memcpy(n->mac_table.macs, elem->out_sg[1].iov_base + sizeof(mac_data),
|
||||
mac_data.entries * ETH_ALEN);
|
||||
s = iov_to_buf(iov, iov_cnt, 0, n->mac_table.macs,
|
||||
mac_data.entries * ETH_ALEN);
|
||||
if (s != mac_data.entries * ETH_ALEN) {
|
||||
return VIRTIO_NET_ERR;
|
||||
}
|
||||
n->mac_table.in_use += mac_data.entries;
|
||||
} else {
|
||||
n->mac_table.uni_overflow = 1;
|
||||
}
|
||||
|
||||
iov_discard_front(&iov, &iov_cnt, mac_data.entries * ETH_ALEN);
|
||||
|
||||
n->mac_table.first_multi = n->mac_table.in_use;
|
||||
|
||||
mac_data.entries = ldl_p(elem->out_sg[2].iov_base);
|
||||
|
||||
if (sizeof(mac_data.entries) +
|
||||
(mac_data.entries * ETH_ALEN) > elem->out_sg[2].iov_len)
|
||||
s = iov_to_buf(iov, iov_cnt, 0, &mac_data.entries,
|
||||
sizeof(mac_data.entries));
|
||||
mac_data.entries = ldl_p(&mac_data.entries);
|
||||
if (s != sizeof(mac_data.entries)) {
|
||||
return VIRTIO_NET_ERR;
|
||||
}
|
||||
|
||||
if (mac_data.entries) {
|
||||
if (n->mac_table.in_use + mac_data.entries <= MAC_TABLE_ENTRIES) {
|
||||
memcpy(n->mac_table.macs + (n->mac_table.in_use * ETH_ALEN),
|
||||
elem->out_sg[2].iov_base + sizeof(mac_data),
|
||||
mac_data.entries * ETH_ALEN);
|
||||
n->mac_table.in_use += mac_data.entries;
|
||||
} else {
|
||||
n->mac_table.multi_overflow = 1;
|
||||
iov_discard_front(&iov, &iov_cnt, s);
|
||||
|
||||
if (mac_data.entries * ETH_ALEN != iov_size(iov, iov_cnt)) {
|
||||
return VIRTIO_NET_ERR;
|
||||
}
|
||||
|
||||
if (n->mac_table.in_use + mac_data.entries <= MAC_TABLE_ENTRIES) {
|
||||
s = iov_to_buf(iov, iov_cnt, 0, n->mac_table.macs,
|
||||
mac_data.entries * ETH_ALEN);
|
||||
if (s != mac_data.entries * ETH_ALEN) {
|
||||
return VIRTIO_NET_ERR;
|
||||
}
|
||||
n->mac_table.in_use += mac_data.entries;
|
||||
} else {
|
||||
n->mac_table.multi_overflow = 1;
|
||||
}
|
||||
|
||||
return VIRTIO_NET_OK;
|
||||
}
|
||||
|
||||
static int virtio_net_handle_vlan_table(VirtIONet *n, uint8_t cmd,
|
||||
VirtQueueElement *elem)
|
||||
struct iovec *iov, unsigned int iov_cnt)
|
||||
{
|
||||
uint16_t vid;
|
||||
size_t s;
|
||||
|
||||
if (elem->out_num != 2 || elem->out_sg[1].iov_len != sizeof(vid)) {
|
||||
error_report("virtio-net ctrl invalid vlan command");
|
||||
s = iov_to_buf(iov, iov_cnt, 0, &vid, sizeof(vid));
|
||||
vid = lduw_p(&vid);
|
||||
if (s != sizeof(vid)) {
|
||||
return VIRTIO_NET_ERR;
|
||||
}
|
||||
|
||||
vid = lduw_p(elem->out_sg[1].iov_base);
|
||||
|
||||
if (vid >= MAX_VLAN)
|
||||
return VIRTIO_NET_ERR;
|
||||
|
||||
|
@ -427,30 +457,33 @@ static void virtio_net_handle_ctrl(VirtIODevice *vdev, VirtQueue *vq)
|
|||
struct virtio_net_ctrl_hdr ctrl;
|
||||
virtio_net_ctrl_ack status = VIRTIO_NET_ERR;
|
||||
VirtQueueElement elem;
|
||||
size_t s;
|
||||
struct iovec *iov;
|
||||
unsigned int iov_cnt;
|
||||
|
||||
while (virtqueue_pop(vq, &elem)) {
|
||||
if ((elem.in_num < 1) || (elem.out_num < 1)) {
|
||||
if (iov_size(elem.in_sg, elem.in_num) < sizeof(status) ||
|
||||
iov_size(elem.out_sg, elem.out_num) < sizeof(ctrl)) {
|
||||
error_report("virtio-net ctrl missing headers");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (elem.out_sg[0].iov_len < sizeof(ctrl) ||
|
||||
elem.in_sg[elem.in_num - 1].iov_len < sizeof(status)) {
|
||||
error_report("virtio-net ctrl header not in correct element");
|
||||
exit(1);
|
||||
iov = elem.out_sg;
|
||||
iov_cnt = elem.out_num;
|
||||
s = iov_to_buf(iov, iov_cnt, 0, &ctrl, sizeof(ctrl));
|
||||
iov_discard_front(&iov, &iov_cnt, sizeof(ctrl));
|
||||
if (s != sizeof(ctrl)) {
|
||||
status = VIRTIO_NET_ERR;
|
||||
} else if (ctrl.class == VIRTIO_NET_CTRL_RX) {
|
||||
status = virtio_net_handle_rx_mode(n, ctrl.cmd, iov, iov_cnt);
|
||||
} else if (ctrl.class == VIRTIO_NET_CTRL_MAC) {
|
||||
status = virtio_net_handle_mac(n, ctrl.cmd, iov, iov_cnt);
|
||||
} else if (ctrl.class == VIRTIO_NET_CTRL_VLAN) {
|
||||
status = virtio_net_handle_vlan_table(n, ctrl.cmd, iov, iov_cnt);
|
||||
}
|
||||
|
||||
ctrl.class = ldub_p(elem.out_sg[0].iov_base);
|
||||
ctrl.cmd = ldub_p(elem.out_sg[0].iov_base + sizeof(ctrl.class));
|
||||
|
||||
if (ctrl.class == VIRTIO_NET_CTRL_RX_MODE)
|
||||
status = virtio_net_handle_rx_mode(n, ctrl.cmd, &elem);
|
||||
else if (ctrl.class == VIRTIO_NET_CTRL_MAC)
|
||||
status = virtio_net_handle_mac(n, ctrl.cmd, &elem);
|
||||
else if (ctrl.class == VIRTIO_NET_CTRL_VLAN)
|
||||
status = virtio_net_handle_vlan_table(n, ctrl.cmd, &elem);
|
||||
|
||||
stb_p(elem.in_sg[elem.in_num - 1].iov_base, status);
|
||||
s = iov_from_buf(elem.in_sg, elem.in_num, 0, &status, sizeof(status));
|
||||
assert(s == sizeof(status));
|
||||
|
||||
virtqueue_push(vq, &elem, sizeof(status));
|
||||
virtio_notify(vdev, vq);
|
||||
|
|
|
@ -44,6 +44,8 @@
|
|||
#define VIRTIO_NET_F_CTRL_VLAN 19 /* Control channel VLAN filtering */
|
||||
#define VIRTIO_NET_F_CTRL_RX_EXTRA 20 /* Extra RX mode control support */
|
||||
|
||||
#define VIRTIO_NET_F_CTRL_MAC_ADDR 23 /* Set MAC address */
|
||||
|
||||
#define VIRTIO_NET_S_LINK_UP 1 /* Link is up */
|
||||
|
||||
#define TX_TIMER_INTERVAL 150000 /* 150 us */
|
||||
|
@ -97,16 +99,16 @@ typedef uint8_t virtio_net_ctrl_ack;
|
|||
* 0 and 1 are supported with the VIRTIO_NET_F_CTRL_RX feature.
|
||||
* Commands 2-5 are added with VIRTIO_NET_F_CTRL_RX_EXTRA.
|
||||
*/
|
||||
#define VIRTIO_NET_CTRL_RX_MODE 0
|
||||
#define VIRTIO_NET_CTRL_RX_MODE_PROMISC 0
|
||||
#define VIRTIO_NET_CTRL_RX_MODE_ALLMULTI 1
|
||||
#define VIRTIO_NET_CTRL_RX_MODE_ALLUNI 2
|
||||
#define VIRTIO_NET_CTRL_RX_MODE_NOMULTI 3
|
||||
#define VIRTIO_NET_CTRL_RX_MODE_NOUNI 4
|
||||
#define VIRTIO_NET_CTRL_RX_MODE_NOBCAST 5
|
||||
#define VIRTIO_NET_CTRL_RX 0
|
||||
#define VIRTIO_NET_CTRL_RX_PROMISC 0
|
||||
#define VIRTIO_NET_CTRL_RX_ALLMULTI 1
|
||||
#define VIRTIO_NET_CTRL_RX_ALLUNI 2
|
||||
#define VIRTIO_NET_CTRL_RX_NOMULTI 3
|
||||
#define VIRTIO_NET_CTRL_RX_NOUNI 4
|
||||
#define VIRTIO_NET_CTRL_RX_NOBCAST 5
|
||||
|
||||
/*
|
||||
* Control the MAC filter table.
|
||||
* Control the MAC
|
||||
*
|
||||
* The MAC filter table is managed by the hypervisor, the guest should
|
||||
* assume the size is infinite. Filtering should be considered
|
||||
|
@ -119,6 +121,10 @@ typedef uint8_t virtio_net_ctrl_ack;
|
|||
* first sg list contains unicast addresses, the second is for multicast.
|
||||
* This functionality is present if the VIRTIO_NET_F_CTRL_RX feature
|
||||
* is available.
|
||||
*
|
||||
* The ADDR_SET command requests one out scatterlist, it contains a
|
||||
* 6 bytes MAC address. This functionality is present if the
|
||||
* VIRTIO_NET_F_CTRL_MAC_ADDR feature is available.
|
||||
*/
|
||||
struct virtio_net_ctrl_mac {
|
||||
uint32_t entries;
|
||||
|
@ -126,6 +132,7 @@ struct virtio_net_ctrl_mac {
|
|||
};
|
||||
#define VIRTIO_NET_CTRL_MAC 1
|
||||
#define VIRTIO_NET_CTRL_MAC_TABLE_SET 0
|
||||
#define VIRTIO_NET_CTRL_MAC_ADDR_SET 1
|
||||
|
||||
/*
|
||||
* Control VLAN filtering
|
||||
|
@ -158,5 +165,6 @@ struct virtio_net_ctrl_mac {
|
|||
DEFINE_PROP_BIT("ctrl_vq", _state, _field, VIRTIO_NET_F_CTRL_VQ, true), \
|
||||
DEFINE_PROP_BIT("ctrl_rx", _state, _field, VIRTIO_NET_F_CTRL_RX, true), \
|
||||
DEFINE_PROP_BIT("ctrl_vlan", _state, _field, VIRTIO_NET_F_CTRL_VLAN, true), \
|
||||
DEFINE_PROP_BIT("ctrl_rx_extra", _state, _field, VIRTIO_NET_F_CTRL_RX_EXTRA, true)
|
||||
DEFINE_PROP_BIT("ctrl_rx_extra", _state, _field, VIRTIO_NET_F_CTRL_RX_EXTRA, true), \
|
||||
DEFINE_PROP_BIT("ctrl_mac_addr", _state, _field, VIRTIO_NET_F_CTRL_MAC_ADDR, true)
|
||||
#endif
|
||||
|
|
14
rules.mak
14
rules.mak
|
@ -82,12 +82,16 @@ TRACETOOL=$(PYTHON) $(SRC_PATH)/scripts/tracetool.py
|
|||
|
||||
# Generate timestamp files for .h include files
|
||||
|
||||
%.h: %.h-timestamp
|
||||
@test -f $@ || cp $< $@
|
||||
config-%.h: config-%.h-timestamp
|
||||
@cmp $< $@ >/dev/null 2>&1 || cp $< $@
|
||||
|
||||
%.h-timestamp: %.mak
|
||||
$(call quiet-command, sh $(SRC_PATH)/scripts/create_config < $< > $@, " GEN $(TARGET_DIR)$*.h")
|
||||
@cmp $@ $*.h >/dev/null 2>&1 || cp $@ $*.h
|
||||
config-%.h-timestamp: config-%.mak
|
||||
$(call quiet-command, sh $(SRC_PATH)/scripts/create_config < $< > $@, " GEN $(TARGET_DIR)config-$*.h")
|
||||
|
||||
.PHONY: clean-timestamp
|
||||
clean-timestamp:
|
||||
rm -f *.timestamp
|
||||
clean: clean-timestamp
|
||||
|
||||
# will delete the target of a rule if commands exit with a nonzero exit status
|
||||
.DELETE_ON_ERROR:
|
||||
|
|
|
@ -4,24 +4,24 @@
|
|||
# Auto-generated header for tracing routines
|
||||
|
||||
$(obj)/generated-tracers.h: $(obj)/generated-tracers.h-timestamp
|
||||
@cmp -s $< $@ || cp $< $@
|
||||
$(obj)/generated-tracers.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
|
||||
$(call quiet-command,$(TRACETOOL) \
|
||||
--format=h \
|
||||
--backend=$(TRACE_BACKEND) \
|
||||
< $< > $@," GEN $(patsubst %-timestamp,%,$@)")
|
||||
@cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@)
|
||||
|
||||
######################################################################
|
||||
# Auto-generated tracing routines (non-DTrace)
|
||||
|
||||
ifneq ($(TRACE_BACKEND),dtrace)
|
||||
$(obj)/generated-tracers.c: $(obj)/generated-tracers.c-timestamp
|
||||
@cmp -s $< $@ || cp $< $@
|
||||
$(obj)/generated-tracers.c-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
|
||||
$(call quiet-command,$(TRACETOOL) \
|
||||
--format=c \
|
||||
--backend=$(TRACE_BACKEND) \
|
||||
< $< > $@," GEN $(patsubst %-timestamp,%,$@)")
|
||||
@cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@)
|
||||
|
||||
$(obj)/generated-tracers.o: $(obj)/generated-tracers.c $(obj)/generated-tracers.h
|
||||
endif
|
||||
|
|
Loading…
Reference in New Issue