[PATCH 00/12] Multiqueue virtio-net

2012-12-28 Thread Jason Wang
Hello all:

This seires is an update of last version of multiqueue virtio-net support.

Recently, linux tap gets multiqueue support. This series implements basic
support for multiqueue tap, nic and vhost. Then use it as an infrastructure to
enable the multiqueue support for virtio-net.

Both vhost and userspace multiqueue were implemented for virtio-net, but
userspace could be get much benefits since dataplane like parallized mechanism
were not implemented.

User could start a multiqueue virtio-net card through adding a queues
parameter to tap.

./qemu -netdev tap,id=hn0,queues=2,vhost=on -device virtio-net-pci,netdev=hn0

Management tools such as libvirt can pass multiple pre-created fds through

./qemu -netdev tap,id=hn0,queues=2,fd=X,fd=Y -device virtio-net-pci,netdev=hn0

You can fetch and try the code from:
git://github.com/jasowang/qemu.git

Patch 1 adds a generic method of creating multiqueue taps and implement the
linux part.
Patch 2 - 4 introduce some helpers which could be used to refactor the nic
emulation codes to support multiqueue.
Patch 5 introduces multiqueue support for qemu networking code: each peers of
NetClientState were abstracted as a queue. Though this, most of the codes could
be reusued without change.
Patch 6 adds basic multiqueue support for vhost which could let vhost just
handle a subset of all virtqueues.
Patch 7-8 introduce new helpers of virtio which is needed by multiqueue
virtio-net.
Patch 9-12 implement the multiqueue support of virtio-net

Changes from RFC v2:
- rebase the codes to latest qemu
- align the multiqueue virtio-net implementation to virtio spec
- split the patches into more smaller patches
- set_link and hotplug support

Changes from RFC V1:
- rebase to the latest
- fix memory leak in parse_netdev
- fix guest notifiers assignment/de-assignment
- changes the command lines to:
   qemu -netdev tap,queues=2 -device virtio-net-pci,queues=2

Reference:
v2: http://lists.gnu.org/archive/html/qemu-devel/2012-06/msg04108.html
v1: http://comments.gmane.org/gmane.comp.emulators.qemu/100481

Perf Numbers:

Two Intel Xeon 5620 with direct connected intel 82599EB
Host/Guest kernel: David net tree
vhost enabled

- lots of improvents of both latency and cpu utilization in request-reponse test
- get regression of guest sending small packets which because TCP tends to batch
  less when the latency were improved

1q/2q/4q
TCP_RR
 size #sessions trans.rate  norm trans.rate  norm trans.rate  norm
1 1 9393.26   595.64  9408.18   597.34  9375.19   584.12
1 2072162.1   2214.24 129880.22 2456.13 196949.81 2298.13
1 50107513.38 2653.99 139721.93 2490.58 259713.82 2873.57
1 100   126734.63 2676.54 145553.5  2406.63 265252.68 2943
64 19453.42   632.33  9371.37   616.13  9338.19   615.97
64 20   70620.03  2093.68 125155.75 2409.15 191239.91 2253.32
64 50   1069662448.29 146518.67 2514.47 242134.07 2720.91
64 100  117046.35 2394.56 190153.09 2696.82 238881.29 2704.41
256 1   8733.29   736.36  8701.07   680.83  8608.92   530.1
256 20  69279.89  2274.45 115103.07 2299.76 144555.16 1963.53
256 50  97676.02  2296.09 150719.57 2522.92 254510.5  3028.44
256 100 150221.55 2949.56 197569.3  2790.92 300695.78 3494.83
TCP_CRR
 size #sessions trans.rate  norm trans.rate  norm trans.rate  norm
1 1 2848.37  163.41 2230.39  130.89 2013.09  120.47
1 2023434.5  562.11 31057.43 531.07 49488.28 564.41
1 5028514.88 582.17 40494.23 605.92 60113.35 654.97
1 100   28827.22 584.73 48813.25 661.6  61783.62 676.56
64 12780.08  159.4  2201.07  127.96 2006.8   117.63
64 20   23318.51 564.47 30982.44 530.24 49734.95 566.13
64 50   28585.72 582.54 40576.7  610.08 60167.89 656.56
64 100  28747.37 584.17 49081.87 667.87 60612.94 662
256 1   2772.08  160.51 2231.84  131.05 2003.62  113.45
256 20  23086.35 559.8  30929.09 528.16 48454.9  555.22
256 50  28354.7  579.85 40578.31 60760261.71 657.87
256 100 28844.55 585.67 48541.86 659.08 61941.07 676.72
TCP_STREAM guest receiving
 size #sessions throughput  norm throughput  norm throughput  norm
1 1 16.27   1.33   16.11.12   16.13   0.99
1 2 33.04   2.08   32.96   2.19   32.75   1.98
1 4 66.62   6.83   68.35.56   66.14   2.65
64 1896.55  56.67  914.02  58.14  898.9   61.56
64 21830.46 91.02  1812.02 64.59  1835.57 66.26
64 43626.61 142.55 3636.25 100.64 3607.46 75.03
256 1   2619.49 131.23 2543.19 129.03 2618.69 132.39
256 2   5136.58 203.02 5163.31 141.11 5236.51 149.4
256 4   7063.99 242.83 9365.4  208.49 9421.03 159.94
512 1   3592.43 165.24 3603.12 167.19 3552.5  169.57
512 2   7042.62 246.59 7068.46 180.87 7258.52 186.3
512 4   6996.08 241.49 9298.34 206.12 9418.52 159.33
1024 1  4339.54 192.95 4370.2  191.92 4211.72 192.49
1024 2  7439.45 254.77 9403.99 215.24 9120.82 222.67
1024 4  7953.86 272.11 9403.87 208.23 9366.98 159.49
4096 1  7696.28 272.04 7611.41 270.38 7778.71 267.76
4096 2  7530.35 261.1  8905.43 246.27 8990.18 267.57
4096 4  7121.6  247.02 9411.75 206.71 9654.96 184.67
16384 1 

[PATCH 01/12] tap: multiqueue support

2012-12-28 Thread Jason Wang
Recently, linux support multiqueue tap which could let userspace call TUNSETIFF
for a signle device many times to create multiple file descriptors as
independent queues. User could also enable/disabe a specific queue through
TUNSETQUEUE.

The patch adds the generic infrastructure to create multiqueue taps. To achieve
this a new parameter queues were introduced to specify how many queues were
expected to be created for tap. The fd parameter were also changed to support
a list of file descriptors which could be used by management (such as libvirt)
to pass pre-created file descriptors (queues) to qemu.

Each TAPState were still associated to a tap fd, which mean multiple TAPStates
were created when user needs multiqueue taps.

Only linux part were implemented now, since it's the only OS that support
multiqueue tap.

Signed-off-by: Jason Wang jasow...@redhat.com
---
 net/tap-aix.c |   18 -
 net/tap-bsd.c |   18 -
 net/tap-haiku.c   |   18 -
 net/tap-linux.c   |   70 +++-
 net/tap-linux.h   |4 +
 net/tap-solaris.c |   18 -
 net/tap-win32.c   |   10 ++
 net/tap.c |  248 +
 net/tap.h |8 ++-
 qapi-schema.json  |5 +-
 10 files changed, 335 insertions(+), 82 deletions(-)

diff --git a/net/tap-aix.c b/net/tap-aix.c
index f27c177..f931ef3 100644
--- a/net/tap-aix.c
+++ b/net/tap-aix.c
@@ -25,7 +25,8 @@
 #include net/tap.h
 #include stdio.h
 
-int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int 
vnet_hdr_required)
+int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
+ int vnet_hdr_required, int mq_required)
 {
 fprintf(stderr, no tap on AIX\n);
 return -1;
@@ -59,3 +60,18 @@ void tap_fd_set_offload(int fd, int csum, int tso4,
 int tso6, int ecn, int ufo)
 {
 }
+
+int tap_fd_attach(int fd)
+{
+return -1;
+}
+
+int tap_fd_detach(int fd)
+{
+return -1;
+}
+
+int tap_fd_ifname(int fd, char *ifname)
+{
+return -1;
+}
diff --git a/net/tap-bsd.c b/net/tap-bsd.c
index a3b717d..07c287d 100644
--- a/net/tap-bsd.c
+++ b/net/tap-bsd.c
@@ -33,7 +33,8 @@
 #include net/if_tap.h
 #endif
 
-int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int 
vnet_hdr_required)
+int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
+ int vnet_hdr_required, int mq_required)
 {
 int fd;
 #ifdef TAPGIFNAME
@@ -145,3 +146,18 @@ void tap_fd_set_offload(int fd, int csum, int tso4,
 int tso6, int ecn, int ufo)
 {
 }
+
+int tap_fd_attach(int fd)
+{
+return -1;
+}
+
+int tap_fd_detach(int fd)
+{
+return -1;
+}
+
+int tap_fd_ifname(int fd, char *ifname)
+{
+return -1;
+}
diff --git a/net/tap-haiku.c b/net/tap-haiku.c
index 34739d1..62ab423 100644
--- a/net/tap-haiku.c
+++ b/net/tap-haiku.c
@@ -25,7 +25,8 @@
 #include net/tap.h
 #include stdio.h
 
-int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int 
vnet_hdr_required)
+int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
+ int vnet_hdr_required, int mq_required)
 {
 fprintf(stderr, no tap on Haiku\n);
 return -1;
@@ -59,3 +60,18 @@ void tap_fd_set_offload(int fd, int csum, int tso4,
 int tso6, int ecn, int ufo)
 {
 }
+
+int tap_fd_attach(int fd)
+{
+return -1;
+}
+
+int tap_fd_detach(int fd)
+{
+return -1;
+}
+
+int tap_fd_ifname(int fd, char *ifname)
+{
+return -1;
+}
diff --git a/net/tap-linux.c b/net/tap-linux.c
index c6521be..0854ef5 100644
--- a/net/tap-linux.c
+++ b/net/tap-linux.c
@@ -35,7 +35,8 @@
 
 #define PATH_NET_TUN /dev/net/tun
 
-int tap_open(char *ifname, int ifname_size, int *vnet_hdr, int 
vnet_hdr_required)
+int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
+ int vnet_hdr_required, int mq_required)
 {
 struct ifreq ifr;
 int fd, ret;
@@ -67,6 +68,20 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr, 
int vnet_hdr_required
 }
 }
 
+if (mq_required) {
+unsigned int features;
+
+if ((ioctl(fd, TUNGETFEATURES, features) != 0) ||
+!(features  IFF_MULTI_QUEUE)) {
+error_report(multiqueue required, but no kernel 
+ support for IFF_MULTI_QUEUE available);
+close(fd);
+return -1;
+} else {
+ifr.ifr_flags |= IFF_MULTI_QUEUE;
+}
+}
+
 if (ifname[0] != '\0')
 pstrcpy(ifr.ifr_name, IFNAMSIZ, ifname);
 else
@@ -200,3 +215,56 @@ void tap_fd_set_offload(int fd, int csum, int tso4,
 }
 }
 }
+
+/* Attach a file descriptor to a TUN/TAP device. This descriptor should be
+ * detached before.
+ */
+int tap_fd_attach(int fd)
+{
+struct ifreq ifr;
+int ret;
+
+memset(ifr, 0, sizeof(ifr));
+
+ifr.ifr_flags = IFF_ATTACH_QUEUE;
+ret = ioctl(fd, TUNSETQUEUE, (void *) ifr);
+
+if (ret != 0) {
+error_report(could not attach fd to tap);
+}
+
+return ret;
+}
+

[PATCH 02/12] net: introduce qemu_get_queue()

2012-12-28 Thread Jason Wang
To support multiqueue, the patch introduce a helper qemu_get_queue()
which is used to get the NetClientState of a device. The following patches would
refactor this helper to support multiqueue.

Signed-off-by: Jason Wang jasow...@redhat.com
---
 hw/cadence_gem.c|8 +++---
 hw/dp8393x.c|8 +++---
 hw/e1000.c  |   20 +++---
 hw/eepro100.c   |   12 
 hw/etraxfs_eth.c|4 +-
 hw/lan9118.c|   10 +++---
 hw/mcf_fec.c|4 +-
 hw/milkymist-minimac2.c |4 +-
 hw/mipsnet.c|4 +-
 hw/musicpal.c   |2 +-
 hw/ne2000-isa.c |2 +-
 hw/ne2000.c |6 ++--
 hw/opencores_eth.c  |6 ++--
 hw/pcnet-pci.c  |2 +-
 hw/pcnet.c  |6 ++--
 hw/rtl8139.c|   12 
 hw/smc91c111.c  |4 +-
 hw/spapr_llan.c |4 +-
 hw/stellaris_enet.c |4 +-
 hw/usb/dev-network.c|   10 +++---
 hw/virtio-net.c |   64 +++---
 hw/xen_nic.c|   10 +++---
 hw/xgmac.c  |4 +-
 hw/xilinx_axienet.c |4 +-
 hw/xilinx_ethlite.c |4 +-
 net.c   |5 +++
 net.h   |1 +
 savevm.c|2 +-
 28 files changed, 116 insertions(+), 110 deletions(-)

diff --git a/hw/cadence_gem.c b/hw/cadence_gem.c
index 0c037a2..9d27ecb 100644
--- a/hw/cadence_gem.c
+++ b/hw/cadence_gem.c
@@ -389,10 +389,10 @@ static void gem_init_register_masks(GemState *s)
  */
 static void phy_update_link(GemState *s)
 {
-DB_PRINT(down %d\n, s-nic-nc.link_down);
+DB_PRINT(down %d\n, qemu_get_queue(s-nic)-link_down);
 
 /* Autonegotiation status mirrors link status.  */
-if (s-nic-nc.link_down) {
+if (qemu_get_queue(s-nic)-link_down) {
 s-phy_regs[PHY_REG_STATUS] = ~(PHY_REG_STATUS_ANEGCMPL |
  PHY_REG_STATUS_LINK);
 s-phy_regs[PHY_REG_INT_ST] |= PHY_REG_INT_ST_LINKC;
@@ -906,9 +906,9 @@ static void gem_transmit(GemState *s)
 
 /* Send the packet somewhere */
 if (s-phy_loop) {
-gem_receive(s-nic-nc, tx_packet, total_bytes);
+gem_receive(qemu_get_queue(s-nic), tx_packet, total_bytes);
 } else {
-qemu_send_packet(s-nic-nc, tx_packet, total_bytes);
+qemu_send_packet(qemu_get_queue(s-nic), tx_packet, 
total_bytes);
 }
 
 /* Prepare for next packet */
diff --git a/hw/dp8393x.c b/hw/dp8393x.c
index 3f6386e..db50cc6 100644
--- a/hw/dp8393x.c
+++ b/hw/dp8393x.c
@@ -408,13 +408,13 @@ static void do_transmit_packets(dp8393xState *s)
 if (s-regs[SONIC_RCR]  (SONIC_RCR_LB1 | SONIC_RCR_LB0)) {
 /* Loopback */
 s-regs[SONIC_TCR] |= SONIC_TCR_CRSL;
-if (s-nic-nc.info-can_receive(s-nic-nc)) {
+if 
(qemu_get_queue(s-nic)-info-can_receive(qemu_get_queue(s-nic))) {
 s-loopback_packet = 1;
-s-nic-nc.info-receive(s-nic-nc, s-tx_buffer, tx_len);
+qemu_get_queue(s-nic)-info-receive(qemu_get_queue(s-nic), 
s-tx_buffer, tx_len);
 }
 } else {
 /* Transmit packet */
-qemu_send_packet(s-nic-nc, s-tx_buffer, tx_len);
+qemu_send_packet(qemu_get_queue(s-nic), s-tx_buffer, tx_len);
 }
 s-regs[SONIC_TCR] |= SONIC_TCR_PTX;
 
@@ -903,7 +903,7 @@ void dp83932_init(NICInfo *nd, hwaddr base, int it_shift,
 
 s-nic = qemu_new_nic(net_dp83932_info, s-conf, nd-model, nd-name, s);
 
-qemu_format_nic_info_str(s-nic-nc, s-conf.macaddr.a);
+qemu_format_nic_info_str(qemu_get_queue(s-nic), s-conf.macaddr.a);
 qemu_register_reset(nic_reset, s);
 nic_reset(s);
 
diff --git a/hw/e1000.c b/hw/e1000.c
index 5537ad2..aaa4f88 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -164,7 +164,7 @@ static void
 set_phy_ctrl(E1000State *s, int index, uint16_t val)
 {
 if ((val  MII_CR_AUTO_NEG_EN)  (val  MII_CR_RESTART_AUTO_NEG)) {
-s-nic-nc.link_down = true;
+qemu_get_queue(s-nic)-link_down = true;
 e1000_link_down(s);
 s-phy_reg[PHY_STATUS] = ~MII_SR_AUTONEG_COMPLETE;
 DBGOUT(PHY, Start link auto negotiation\n);
@@ -176,7 +176,7 @@ static void
 e1000_autoneg_timer(void *opaque)
 {
 E1000State *s = opaque;
-s-nic-nc.link_down = false;
+qemu_get_queue(s-nic)-link_down = false;
 e1000_link_up(s);
 s-phy_reg[PHY_STATUS] |= MII_SR_AUTONEG_COMPLETE;
 DBGOUT(PHY, Auto negotiation is completed\n);
@@ -279,7 +279,7 @@ static void e1000_reset(void *opaque)
 d-rxbuf_min_shift = 1;
 memset(d-tx, 0, sizeof d-tx);
 
-if (d-nic-nc.link_down) {
+if (qemu_get_queue(d-nic)-link_down) {
 e1000_link_down(d);
 }
 
@@ -307,7 +307,7 @@ set_rx_control(E1000State *s, int index, uint32_t val)
 s-rxbuf_min_shift = ((val / 

[PATCH 04/12] net: intorduce qemu_del_nic()

2012-12-28 Thread Jason Wang
To support multiqueue nic, this patch separate the nic destructor from
qemu_del_net_client() to a new helper qemu_del_nic(). The following patches
would refactor this function to support multiqueue nic.

Signed-off-by: Jason Wang jasow...@redhat.com
---
 hw/e1000.c   |2 +-
 hw/eepro100.c|2 +-
 hw/ne2000.c  |2 +-
 hw/pcnet-pci.c   |2 +-
 hw/rtl8139.c |2 +-
 hw/usb/dev-network.c |2 +-
 hw/virtio-net.c  |2 +-
 hw/xen_nic.c |2 +-
 net.c|   15 ++-
 net.h|1 +
 10 files changed, 23 insertions(+), 9 deletions(-)

diff --git a/hw/e1000.c b/hw/e1000.c
index 004f057..eb181d8 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -1234,7 +1234,7 @@ pci_e1000_uninit(PCIDevice *dev)
 qemu_free_timer(d-autoneg_timer);
 memory_region_destroy(d-mmio);
 memory_region_destroy(d-io);
-qemu_del_net_client(qemu_get_queue(d-nic));
+qemu_del_nic(d-nic);
 }
 
 static NetClientInfo net_e1000_info = {
diff --git a/hw/eepro100.c b/hw/eepro100.c
index c09a315..d072131 100644
--- a/hw/eepro100.c
+++ b/hw/eepro100.c
@@ -1849,7 +1849,7 @@ static void pci_nic_uninit(PCIDevice *pci_dev)
 memory_region_destroy(s-flash_bar);
 vmstate_unregister(pci_dev-qdev, s-vmstate, s);
 eeprom93xx_free(pci_dev-qdev, s-eeprom);
-qemu_del_net_client(qemu_get_queue(s-nic));
+qemu_del_nic(s-nic);
 }
 
 static NetClientInfo net_eepro100_info = {
diff --git a/hw/ne2000.c b/hw/ne2000.c
index 64b73fe..e6810ad 100644
--- a/hw/ne2000.c
+++ b/hw/ne2000.c
@@ -750,7 +750,7 @@ static void pci_ne2000_exit(PCIDevice *pci_dev)
 NE2000State *s = d-ne2000;
 
 memory_region_destroy(s-io);
-qemu_del_net_client(qemu_get_queue(s-nic));
+qemu_del_nic(s-nic);
 }
 
 static Property ne2000_properties[] = {
diff --git a/hw/pcnet-pci.c b/hw/pcnet-pci.c
index f4a03eb..c910fa3 100644
--- a/hw/pcnet-pci.c
+++ b/hw/pcnet-pci.c
@@ -279,7 +279,7 @@ static void pci_pcnet_uninit(PCIDevice *dev)
 memory_region_destroy(d-io_bar);
 qemu_del_timer(d-state.poll_timer);
 qemu_free_timer(d-state.poll_timer);
-qemu_del_net_client(qemu_get_queue(d-state.nic));
+qemu_del_nic(d-state.nic);
 }
 
 static NetClientInfo net_pci_pcnet_info = {
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index b6cb90e..a8acd19 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -3445,7 +3445,7 @@ static void pci_rtl8139_uninit(PCIDevice *dev)
 }
 qemu_del_timer(s-timer);
 qemu_free_timer(s-timer);
-qemu_del_net_client(qemu_get_queue(s-nic));
+qemu_del_nic(s-nic);
 }
 
 static void rtl8139_set_link_status(NetClientState *nc)
diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c
index 3de6218..6de0521 100644
--- a/hw/usb/dev-network.c
+++ b/hw/usb/dev-network.c
@@ -1329,7 +1329,7 @@ static void usb_net_handle_destroy(USBDevice *dev)
 
 /* TODO: remove the nd_table[] entry */
 rndis_clear_responsequeue(s);
-qemu_del_net_client(qemu_get_queue(s-nic));
+qemu_del_nic(s-nic);
 }
 
 static NetClientInfo net_usbnet_info = {
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index bf6414b..d57a5a5 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -1098,6 +1098,6 @@ void virtio_net_exit(VirtIODevice *vdev)
 qemu_bh_delete(n-tx_bh);
 }
 
-qemu_del_net_client(qemu_get_queue(n-nic));
+qemu_del_nic(n-nic);
 virtio_cleanup(n-vdev);
 }
diff --git a/hw/xen_nic.c b/hw/xen_nic.c
index 055adf4..6275cd3 100644
--- a/hw/xen_nic.c
+++ b/hw/xen_nic.c
@@ -406,7 +406,7 @@ static void net_disconnect(struct XenDevice *xendev)
 netdev-rxs = NULL;
 }
 if (netdev-nic) {
-qemu_del_net_client(qemu_get_queue(netdev-nic));
+qemu_del_nic(netdev-nic);
 netdev-nic = NULL;
 }
 }
diff --git a/net.c b/net.c
index ef5b8c9..97ee542 100644
--- a/net.c
+++ b/net.c
@@ -290,6 +290,15 @@ void qemu_del_net_client(NetClientState *nc)
 return;
 }
 
+assert(nc-info-type != NET_CLIENT_OPTIONS_KIND_NIC);
+
+qemu_cleanup_net_client(nc);
+qemu_free_net_client(nc);
+}
+
+void qemu_del_nic(NICState *nic)
+{
+NetClientState *nc = qemu_get_queue(nic);
 /* If this is a peer NIC and peer has already been deleted, free it now. */
 if (nc-peer  nc-info-type == NET_CLIENT_OPTIONS_KIND_NIC) {
 NICState *nic = qemu_get_nic(nc);
@@ -932,7 +941,11 @@ void net_cleanup(void)
 NetClientState *nc, *next_vc;
 
 QTAILQ_FOREACH_SAFE(nc, net_clients, next, next_vc) {
-qemu_del_net_client(nc);
+if (nc-info-type == NET_CLIENT_OPTIONS_KIND_NIC) {
+qemu_del_nic(qemu_get_nic(nc));
+} else {
+qemu_del_net_client(nc);
+}
 }
 }
 
diff --git a/net.h b/net.h
index 56b79fb..0d53337 100644
--- a/net.h
+++ b/net.h
@@ -77,6 +77,7 @@ NICState *qemu_new_nic(NetClientInfo *info,
const char *model,
const char *name,
void *opaque);
+void 

[PATCH 03/12] net: introduce qemu_get_nic()

2012-12-28 Thread Jason Wang
To support multiqueue , the patch introduce a helper qemu_get_nic() to get the
NICState from a NetClientState. The following patches would refactor this helper
to support multiqueue.

Signed-off-by: Jason Wang jasow...@redhat.com
---
 hw/cadence_gem.c|8 
 hw/dp8393x.c|6 +++---
 hw/e1000.c  |8 
 hw/eepro100.c   |6 +++---
 hw/etraxfs_eth.c|6 +++---
 hw/lan9118.c|6 +++---
 hw/lance.c  |2 +-
 hw/mcf_fec.c|6 +++---
 hw/milkymist-minimac2.c |6 +++---
 hw/mipsnet.c|6 +++---
 hw/musicpal.c   |4 ++--
 hw/ne2000-isa.c |2 +-
 hw/ne2000.c |6 +++---
 hw/opencores_eth.c  |6 +++---
 hw/pcnet-pci.c  |2 +-
 hw/pcnet.c  |6 +++---
 hw/rtl8139.c|8 
 hw/smc91c111.c  |6 +++---
 hw/spapr_llan.c |4 ++--
 hw/stellaris_enet.c |6 +++---
 hw/usb/dev-network.c|6 +++---
 hw/virtio-net.c |   10 +-
 hw/xen_nic.c|4 ++--
 hw/xgmac.c  |6 +++---
 hw/xilinx_axienet.c |6 +++---
 hw/xilinx_ethlite.c |6 +++---
 net.c   |   20 
 net.h   |2 ++
 28 files changed, 92 insertions(+), 78 deletions(-)

diff --git a/hw/cadence_gem.c b/hw/cadence_gem.c
index 9d27ecb..6874de9 100644
--- a/hw/cadence_gem.c
+++ b/hw/cadence_gem.c
@@ -409,7 +409,7 @@ static int gem_can_receive(NetClientState *nc)
 {
 GemState *s;
 
-s = DO_UPCAST(NICState, nc, nc)-opaque;
+s = qemu_get_nic_opaque(nc);
 
 DB_PRINT(\n);
 
@@ -612,7 +612,7 @@ static ssize_t gem_receive(NetClientState *nc, const 
uint8_t *buf, size_t size)
 uint8_trxbuf[2048];
 uint8_t   *rxbuf_ptr;
 
-s = DO_UPCAST(NICState, nc, nc)-opaque;
+s = qemu_get_nic_opaque(nc);
 
 /* Do nothing if receive is not enabled. */
 if (!(s-regs[GEM_NWCTRL]  GEM_NWCTRL_RXENA)) {
@@ -1148,7 +1148,7 @@ static const MemoryRegionOps gem_ops = {
 
 static void gem_cleanup(NetClientState *nc)
 {
-GemState *s = DO_UPCAST(NICState, nc, nc)-opaque;
+GemState *s = qemu_get_nic_opaque(nc);
 
 DB_PRINT(\n);
 s-nic = NULL;
@@ -1157,7 +1157,7 @@ static void gem_cleanup(NetClientState *nc)
 static void gem_set_link(NetClientState *nc)
 {
 DB_PRINT(\n);
-phy_update_link(DO_UPCAST(NICState, nc, nc)-opaque);
+phy_update_link(qemu_get_nic_opaque(nc));
 }
 
 static NetClientInfo net_gem_info = {
diff --git a/hw/dp8393x.c b/hw/dp8393x.c
index db50cc6..8f20a4a 100644
--- a/hw/dp8393x.c
+++ b/hw/dp8393x.c
@@ -675,7 +675,7 @@ static const MemoryRegionOps dp8393x_ops = {
 
 static int nic_can_receive(NetClientState *nc)
 {
-dp8393xState *s = DO_UPCAST(NICState, nc, nc)-opaque;
+dp8393xState *s = qemu_get_nic_opaque(nc);
 
 if (!(s-regs[SONIC_CR]  SONIC_CR_RXEN))
 return 0;
@@ -724,7 +724,7 @@ static int receive_filter(dp8393xState *s, const uint8_t * 
buf, int size)
 
 static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t 
size)
 {
-dp8393xState *s = DO_UPCAST(NICState, nc, nc)-opaque;
+dp8393xState *s = qemu_get_nic_opaque(nc);
 uint16_t data[10];
 int packet_type;
 uint32_t available, address;
@@ -860,7 +860,7 @@ static void nic_reset(void *opaque)
 
 static void nic_cleanup(NetClientState *nc)
 {
-dp8393xState *s = DO_UPCAST(NICState, nc, nc)-opaque;
+dp8393xState *s = qemu_get_nic_opaque(nc);
 
 memory_region_del_subregion(s-address_space, s-mmio);
 memory_region_destroy(s-mmio);
diff --git a/hw/e1000.c b/hw/e1000.c
index aaa4f88..004f057 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -735,7 +735,7 @@ receive_filter(E1000State *s, const uint8_t *buf, int size)
 static void
 e1000_set_link_status(NetClientState *nc)
 {
-E1000State *s = DO_UPCAST(NICState, nc, nc)-opaque;
+E1000State *s = qemu_get_nic_opaque(nc);
 uint32_t old_status = s-mac_reg[STATUS];
 
 if (nc-link_down) {
@@ -769,7 +769,7 @@ static bool e1000_has_rxbufs(E1000State *s, size_t 
total_size)
 static int
 e1000_can_receive(NetClientState *nc)
 {
-E1000State *s = DO_UPCAST(NICState, nc, nc)-opaque;
+E1000State *s = qemu_get_nic_opaque(nc);
 
 return (s-mac_reg[RCTL]  E1000_RCTL_EN)  e1000_has_rxbufs(s, 1);
 }
@@ -785,7 +785,7 @@ static uint64_t rx_desc_base(E1000State *s)
 static ssize_t
 e1000_receive(NetClientState *nc, const uint8_t *buf, size_t size)
 {
-E1000State *s = DO_UPCAST(NICState, nc, nc)-opaque;
+E1000State *s = qemu_get_nic_opaque(nc);
 struct e1000_rx_desc desc;
 dma_addr_t base;
 unsigned int n, rdt;
@@ -1220,7 +1220,7 @@ e1000_mmio_setup(E1000State *d)
 static void
 e1000_cleanup(NetClientState *nc)
 {
-E1000State *s = DO_UPCAST(NICState, nc, nc)-opaque;
+E1000State *s = qemu_get_nic_opaque(nc);
 
 s-nic = NULL;
 }
diff --git a/hw/eepro100.c b/hw/eepro100.c

[PATCH 05/12] net: multiqueue support

2012-12-28 Thread Jason Wang
This patch adds basic multiqueue support for qemu. The idea is simple, an array
of NetClientStates were introduced in NICState, parse_netdev() were extended to
find and match all NetClientStates belongs to the backend and place their
pointers in NICConf. Then qemu_new_nic can setup a N:N mapping between NICStates
that belongs to a nic and NICStates belongs to the netdev. After this, each
peers of a NICStaet were abstracted as a queue.

To adapt this change, set_link/netdev_del command will find all the
NetClientStates of a nic or a netdev, and change all their state in one run.

Signed-off-by: Jason Wang jasow...@redhat.com
---
 hw/dp8393x.c |2 +-
 hw/mcf_fec.c |2 +-
 hw/qdev-properties.c |   46 +++--
 hw/qdev-properties.h |6 +-
 net.c|  172 +-
 net.h|   27 +++-
 6 files changed, 195 insertions(+), 60 deletions(-)

diff --git a/hw/dp8393x.c b/hw/dp8393x.c
index 8f20a4a..fad0837 100644
--- a/hw/dp8393x.c
+++ b/hw/dp8393x.c
@@ -899,7 +899,7 @@ void dp83932_init(NICInfo *nd, hwaddr base, int it_shift,
 s-regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */
 
 s-conf.macaddr = nd-macaddr;
-s-conf.peer = nd-netdev;
+s-conf.peers.ncs[0] = nd-netdev;
 
 s-nic = qemu_new_nic(net_dp83932_info, s-conf, nd-model, nd-name, s);
 
diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c
index 7fc89b5..c298bec 100644
--- a/hw/mcf_fec.c
+++ b/hw/mcf_fec.c
@@ -472,7 +472,7 @@ void mcf_fec_init(MemoryRegion *sysmem, NICInfo *nd,
 memory_region_add_subregion(sysmem, base, s-iomem);
 
 s-conf.macaddr = nd-macaddr;
-s-conf.peer = nd-netdev;
+s-conf.peers[0] = nd-netdev;
 
 s-nic = qemu_new_nic(net_mcf_fec_info, s-conf, nd-model, nd-name, s);
 
diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
index 81d901c..6e45def 100644
--- a/hw/qdev-properties.c
+++ b/hw/qdev-properties.c
@@ -585,16 +585,47 @@ PropertyInfo qdev_prop_chr = {
 
 static int parse_netdev(DeviceState *dev, const char *str, void **ptr)
 {
-NetClientState *netdev = qemu_find_netdev(str);
+NICPeers *peers_ptr = (NICPeers *)ptr;
+NICConf *conf = container_of(peers_ptr, NICConf, peers);
+NetClientState **ncs = peers_ptr-ncs;
+NetClientState *peers[MAX_QUEUE_NUM];
+int queues, i = 0;
+int ret;
 
-if (netdev == NULL) {
-return -ENOENT;
+queues = qemu_find_net_clients_except(str, peers,
+  NET_CLIENT_OPTIONS_KIND_NIC,
+  MAX_QUEUE_NUM);
+if (queues == 0) {
+ret = -ENOENT;
+goto err;
 }
-if (netdev-peer) {
-return -EEXIST;
+
+if (queues  MAX_QUEUE_NUM) {
+ret = -E2BIG;
+goto err;
+}
+
+for (i = 0; i  queues; i++) {
+if (peers[i] == NULL) {
+ret = -ENOENT;
+goto err;
+}
+
+if (peers[i]-peer) {
+ret = -EEXIST;
+goto err;
+}
+
+ncs[i] = peers[i];
+ncs[i]-queue_index = i;
 }
-*ptr = netdev;
+
+conf-queues = queues;
+
 return 0;
+
+err:
+return ret;
 }
 
 static const char *print_netdev(void *ptr)
@@ -661,7 +692,8 @@ static void set_vlan(Object *obj, Visitor *v, void *opaque,
 {
 DeviceState *dev = DEVICE(obj);
 Property *prop = opaque;
-NetClientState **ptr = qdev_get_prop_ptr(dev, prop);
+NICPeers *peers_ptr = qdev_get_prop_ptr(dev, prop);
+NetClientState **ptr = peers_ptr-ncs[0];
 Error *local_err = NULL;
 int32_t id;
 NetClientState *hubport;
diff --git a/hw/qdev-properties.h b/hw/qdev-properties.h
index 5b046ab..2d90848 100644
--- a/hw/qdev-properties.h
+++ b/hw/qdev-properties.h
@@ -31,7 +31,7 @@ extern PropertyInfo qdev_prop_pci_host_devaddr;
 .name  = (_name),\
 .info  = (_prop),   \
 .offset= offsetof(_state, _field)\
-+ type_check(_type,typeof_field(_state, _field)),\
++ type_check(_type, typeof_field(_state, _field)),   \
 }
 #define DEFINE_PROP_DEFAULT(_name, _state, _field, _defval, _prop, _type) { \
 .name  = (_name),   \
@@ -77,9 +77,9 @@ extern PropertyInfo qdev_prop_pci_host_devaddr;
 #define DEFINE_PROP_STRING(_n, _s, _f) \
 DEFINE_PROP(_n, _s, _f, qdev_prop_string, char*)
 #define DEFINE_PROP_NETDEV(_n, _s, _f) \
-DEFINE_PROP(_n, _s, _f, qdev_prop_netdev, NetClientState*)
+DEFINE_PROP(_n, _s, _f, qdev_prop_netdev, NICPeers)
 #define DEFINE_PROP_VLAN(_n, _s, _f) \
-DEFINE_PROP(_n, _s, _f, qdev_prop_vlan, NetClientState*)
+DEFINE_PROP(_n, _s, _f, qdev_prop_vlan, NICPeers)
 #define DEFINE_PROP_DRIVE(_n, _s, _f) \
 DEFINE_PROP(_n, _s, _f, qdev_prop_drive, BlockDriverState *)
 #define 

[PATCH 06/12] vhost: multiqueue support

2012-12-28 Thread Jason Wang
This patch lets vhost support multiqueue. The idea is simple, just launching
multiple threads of vhost and let each of vhost thread processing a subset of
the virtqueues of the device.

The only thing needed is passing a virtqueue index when starting vhost device,
this is used to track the first virtqueue which this vhost thread serves.

Signed-off-by: Jason Wang jasow...@redhat.com
---
 hw/vhost.c  |   52 +---
 hw/vhost.h  |2 ++
 hw/vhost_net.c  |7 +--
 hw/vhost_net.h  |2 +-
 hw/virtio-net.c |3 ++-
 5 files changed, 43 insertions(+), 23 deletions(-)

diff --git a/hw/vhost.c b/hw/vhost.c
index 16322a1..63c76d6 100644
--- a/hw/vhost.c
+++ b/hw/vhost.c
@@ -619,11 +619,12 @@ static int vhost_virtqueue_init(struct vhost_dev *dev,
 {
 hwaddr s, l, a;
 int r;
+int vhost_vq_index = idx % dev-nvqs;
 struct vhost_vring_file file = {
-.index = idx,
+.index = vhost_vq_index
 };
 struct vhost_vring_state state = {
-.index = idx,
+.index = vhost_vq_index
 };
 struct VirtQueue *vvq = virtio_get_queue(vdev, idx);
 
@@ -669,11 +670,12 @@ static int vhost_virtqueue_init(struct vhost_dev *dev,
 goto fail_alloc_ring;
 }
 
-r = vhost_virtqueue_set_addr(dev, vq, idx, dev-log_enabled);
+r = vhost_virtqueue_set_addr(dev, vq, vhost_vq_index, dev-log_enabled);
 if (r  0) {
 r = -errno;
 goto fail_alloc;
 }
+
 file.fd = event_notifier_get_fd(virtio_queue_get_host_notifier(vvq));
 r = ioctl(dev-control, VHOST_SET_VRING_KICK, file);
 if (r) {
@@ -714,7 +716,7 @@ static void vhost_virtqueue_cleanup(struct vhost_dev *dev,
 unsigned idx)
 {
 struct vhost_vring_state state = {
-.index = idx,
+.index = idx % dev-nvqs,
 };
 int r;
 r = ioctl(dev-control, VHOST_GET_VRING_BASE, state);
@@ -829,7 +831,9 @@ int vhost_dev_enable_notifiers(struct vhost_dev *hdev, 
VirtIODevice *vdev)
 }
 
 for (i = 0; i  hdev-nvqs; ++i) {
-r = vdev-binding-set_host_notifier(vdev-binding_opaque, i, true);
+r = vdev-binding-set_host_notifier(vdev-binding_opaque,
+ hdev-vq_index + i,
+ true);
 if (r  0) {
 fprintf(stderr, vhost VQ %d notifier binding failed: %d\n, i, 
-r);
 goto fail_vq;
@@ -839,7 +843,9 @@ int vhost_dev_enable_notifiers(struct vhost_dev *hdev, 
VirtIODevice *vdev)
 return 0;
 fail_vq:
 while (--i = 0) {
-r = vdev-binding-set_host_notifier(vdev-binding_opaque, i, false);
+r = vdev-binding-set_host_notifier(vdev-binding_opaque,
+ hdev-vq_index + i,
+ false);
 if (r  0) {
 fprintf(stderr, vhost VQ %d notifier cleanup error: %d\n, i, -r);
 fflush(stderr);
@@ -860,7 +866,9 @@ void vhost_dev_disable_notifiers(struct vhost_dev *hdev, 
VirtIODevice *vdev)
 int i, r;
 
 for (i = 0; i  hdev-nvqs; ++i) {
-r = vdev-binding-set_host_notifier(vdev-binding_opaque, i, false);
+r = vdev-binding-set_host_notifier(vdev-binding_opaque,
+ hdev-vq_index + i,
+ false);
 if (r  0) {
 fprintf(stderr, vhost VQ %d notifier cleanup failed: %d\n, i, 
-r);
 fflush(stderr);
@@ -879,10 +887,12 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice 
*vdev)
 goto fail;
 }
 
-r = vdev-binding-set_guest_notifiers(vdev-binding_opaque, true);
-if (r  0) {
-fprintf(stderr, Error binding guest notifier: %d\n, -r);
-goto fail_notifiers;
+if (hdev-vq_index == 0) {
+r = vdev-binding-set_guest_notifiers(vdev-binding_opaque, true);
+if (r  0) {
+fprintf(stderr, Error binding guest notifier: %d\n, -r);
+goto fail_notifiers;
+}
 }
 
 r = vhost_dev_set_features(hdev, hdev-log_enabled);
@@ -898,7 +908,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice 
*vdev)
 r = vhost_virtqueue_init(hdev,
  vdev,
  hdev-vqs + i,
- i);
+ hdev-vq_index + i);
 if (r  0) {
 goto fail_vq;
 }
@@ -925,8 +935,9 @@ fail_vq:
 vhost_virtqueue_cleanup(hdev,
 vdev,
 hdev-vqs + i,
-i);
+hdev-vq_index + i);
 }
+i = hdev-nvqs;
 fail_mem:
 fail_features:
 vdev-binding-set_guest_notifiers(vdev-binding_opaque, false);
@@ -944,21 +955,24 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice 
*vdev)
 

[PATCH 08/12] virtio: add a queue_index to VirtQueue

2012-12-28 Thread Jason Wang
Add a queue_index to VirtQueue and a helper to fetch it, this could be used by
multiqueue supported device.

Signed-off-by: Jason Wang jasow...@redhat.com
---
 hw/virtio.c |8 
 hw/virtio.h |1 +
 2 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/hw/virtio.c b/hw/virtio.c
index bc3c9c3..726c139 100644
--- a/hw/virtio.c
+++ b/hw/virtio.c
@@ -72,6 +72,8 @@ struct VirtQueue
 /* Notification enabled? */
 bool notification;
 
+uint16_t queue_index;
+
 int inuse;
 
 uint16_t vector;
@@ -929,6 +931,7 @@ VirtIODevice *virtio_common_init(const char *name, uint16_t 
device_id,
 for(i = 0; i  VIRTIO_PCI_QUEUE_MAX; i++) {
 vdev-vq[i].vector = VIRTIO_NO_VECTOR;
 vdev-vq[i].vdev = vdev;
+vdev-vq[i].queue_index = i;
 }
 
 vdev-name = name;
@@ -1008,6 +1011,11 @@ VirtQueue *virtio_get_queue(VirtIODevice *vdev, int n)
 return vdev-vq + n;
 }
 
+uint16_t virtio_get_queue_index(VirtQueue *vq)
+{
+return vq-queue_index;
+}
+
 static void virtio_queue_guest_notifier_read(EventNotifier *n)
 {
 VirtQueue *vq = container_of(n, VirtQueue, guest_notifier);
diff --git a/hw/virtio.h b/hw/virtio.h
index f6cb0f9..07b38d6 100644
--- a/hw/virtio.h
+++ b/hw/virtio.h
@@ -237,6 +237,7 @@ hwaddr virtio_queue_get_ring_size(VirtIODevice *vdev, int 
n);
 uint16_t virtio_queue_get_last_avail_idx(VirtIODevice *vdev, int n);
 void virtio_queue_set_last_avail_idx(VirtIODevice *vdev, int n, uint16_t idx);
 VirtQueue *virtio_get_queue(VirtIODevice *vdev, int n);
+uint16_t virtio_get_queue_index(VirtQueue *vq);
 int virtio_queue_get_id(VirtQueue *vq);
 EventNotifier *virtio_queue_get_guest_notifier(VirtQueue *vq);
 void virtio_queue_set_guest_notifier_fd_handler(VirtQueue *vq, bool assign,
-- 
1.7.1

--
To unsubscribe from this list: send the line unsubscribe kvm in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 09/12] virtio-net: separate virtqueue from VirtIONet

2012-12-28 Thread Jason Wang
To support multiqueue virtio-net, the first step is to separate the virtqueue
related fields from VirtIONet to a new structure VirtIONetQueue. The following
patches will add an array of VirtIONetQueue to VirtIONet based on this patch.

Signed-off-by: Jason Wang jasow...@redhat.com
---
 hw/virtio-net.c |  209 ---
 1 files changed, 121 insertions(+), 88 deletions(-)

diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index 70bc0e6..c6f0915 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -26,28 +26,34 @@
 #define MAC_TABLE_ENTRIES64
 #define MAX_VLAN(1  12)   /* Per 802.1Q definition */
 
+typedef struct VirtIONetQueue {
+VirtQueue *rx_vq;
+VirtQueue *tx_vq;
+QEMUTimer *tx_timer;
+QEMUBH *tx_bh;
+int tx_waiting;
+struct {
+VirtQueueElement elem;
+ssize_t len;
+} async_tx;
+struct VirtIONet *n;
+uint8_t vhost_started;
+} VirtIONetQueue;
+
 typedef struct VirtIONet
 {
 VirtIODevice vdev;
 uint8_t mac[ETH_ALEN];
 uint16_t status;
-VirtQueue *rx_vq;
-VirtQueue *tx_vq;
+VirtIONetQueue vq;
 VirtQueue *ctrl_vq;
 NICState *nic;
-QEMUTimer *tx_timer;
-QEMUBH *tx_bh;
 uint32_t tx_timeout;
 int32_t tx_burst;
-int tx_waiting;
 uint32_t has_vnet_hdr;
 size_t host_hdr_len;
 size_t guest_hdr_len;
 uint8_t has_ufo;
-struct {
-VirtQueueElement elem;
-ssize_t len;
-} async_tx;
 int mergeable_rx_bufs;
 uint8_t promisc;
 uint8_t allmulti;
@@ -55,7 +61,6 @@ typedef struct VirtIONet
 uint8_t nomulti;
 uint8_t nouni;
 uint8_t nobcast;
-uint8_t vhost_started;
 struct {
 int in_use;
 int first_multi;
@@ -67,6 +72,12 @@ typedef struct VirtIONet
 DeviceState *qdev;
 } VirtIONet;
 
+static VirtIONetQueue *virtio_net_get_queue(NetClientState *nc)
+{
+VirtIONet *n = qemu_get_nic_opaque(nc);
+
+return n-vq;
+}
 /* TODO
  * - we could suppress RX interrupt if we were so inclined.
  */
@@ -107,6 +118,8 @@ static bool virtio_net_started(VirtIONet *n, uint8_t status)
 
 static void virtio_net_vhost_status(VirtIONet *n, uint8_t status)
 {
+VirtIONetQueue *q = n-vq;
+
 if (!qemu_get_queue(n-nic)-peer) {
 return;
 }
@@ -117,11 +130,11 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t 
status)
 if (!tap_get_vhost_net(qemu_get_queue(n-nic)-peer)) {
 return;
 }
-if (!!n-vhost_started == virtio_net_started(n, status) 
+if (!!q-vhost_started == virtio_net_started(n, status) 
   !qemu_get_queue(n-nic)-peer-link_down) {
 return;
 }
-if (!n-vhost_started) {
+if (!q-vhost_started) {
 int r;
 if (!vhost_net_query(tap_get_vhost_net(qemu_get_queue(n-nic)-peer), 
n-vdev)) {
 return;
@@ -132,36 +145,37 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t 
status)
 error_report(unable to start vhost net: %d: 
  falling back on userspace virtio, -r);
 } else {
-n-vhost_started = 1;
+q-vhost_started = 1;
 }
 } else {
 vhost_net_stop(tap_get_vhost_net(qemu_get_queue(n-nic)-peer), 
n-vdev);
-n-vhost_started = 0;
+q-vhost_started = 0;
 }
 }
 
 static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
 {
 VirtIONet *n = to_virtio_net(vdev);
+VirtIONetQueue *q = n-vq;
 
 virtio_net_vhost_status(n, status);
 
-if (!n-tx_waiting) {
+if (!q-tx_waiting) {
 return;
 }
 
-if (virtio_net_started(n, status)  !n-vhost_started) {
-if (n-tx_timer) {
-qemu_mod_timer(n-tx_timer,
+if (virtio_net_started(n, status)  !q-vhost_started) {
+if (q-tx_timer) {
+qemu_mod_timer(q-tx_timer,
qemu_get_clock_ns(vm_clock) + n-tx_timeout);
 } else {
-qemu_bh_schedule(n-tx_bh);
+qemu_bh_schedule(q-tx_bh);
 }
 } else {
-if (n-tx_timer) {
-qemu_del_timer(n-tx_timer);
+if (q-tx_timer) {
+qemu_del_timer(q-tx_timer);
 } else {
-qemu_bh_cancel(n-tx_bh);
+qemu_bh_cancel(q-tx_bh);
 }
 }
 }
@@ -470,35 +484,40 @@ static void virtio_net_handle_rx(VirtIODevice *vdev, 
VirtQueue *vq)
 static int virtio_net_can_receive(NetClientState *nc)
 {
 VirtIONet *n = qemu_get_nic_opaque(nc);
+VirtIONetQueue *q = virtio_net_get_queue(nc);
+
 if (!n-vdev.vm_running) {
 return 0;
 }
 
-if (!virtio_queue_ready(n-rx_vq) ||
-!(n-vdev.status  VIRTIO_CONFIG_S_DRIVER_OK))
+if (!virtio_queue_ready(q-rx_vq) ||
+!(n-vdev.status  VIRTIO_CONFIG_S_DRIVER_OK)) {
 return 0;
+}
 
 return 1;
 }
 
-static int virtio_net_has_buffers(VirtIONet *n, int bufsize)
+static int virtio_net_has_buffers(VirtIONetQueue *q, int bufsize)

[PATCH 10/12] virtio-net: multiqueue support

2012-12-28 Thread Jason Wang
This patch implements both userspace and vhost support for multiple queue
virtio-net (VIRTIO_NET_F_MQ). This is done by introducing an array of
VirtIONetQueue to VirtIONet.

Signed-off-by: Jason Wang jasow...@redhat.com
---
 hw/virtio-net.c |  318 ++-
 hw/virtio-net.h |   27 +-
 2 files changed, 271 insertions(+), 74 deletions(-)

diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index c6f0915..aaeef1b 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -45,7 +45,7 @@ typedef struct VirtIONet
 VirtIODevice vdev;
 uint8_t mac[ETH_ALEN];
 uint16_t status;
-VirtIONetQueue vq;
+VirtIONetQueue vqs[MAX_QUEUE_NUM];
 VirtQueue *ctrl_vq;
 NICState *nic;
 uint32_t tx_timeout;
@@ -70,14 +70,23 @@ typedef struct VirtIONet
 } mac_table;
 uint32_t *vlans;
 DeviceState *qdev;
+int multiqueue;
+uint16_t max_queues;
+uint16_t curr_queues;
 } VirtIONet;
 
-static VirtIONetQueue *virtio_net_get_queue(NetClientState *nc)
+static VirtIONetQueue *virtio_net_get_subqueue(NetClientState *nc)
 {
 VirtIONet *n = qemu_get_nic_opaque(nc);
 
-return n-vq;
+return n-vqs[nc-queue_index];
 }
+
+static int vq2q(int queue_index)
+{
+return queue_index / 2;
+}
+
 /* TODO
  * - we could suppress RX interrupt if we were so inclined.
  */
@@ -93,6 +102,7 @@ static void virtio_net_get_config(VirtIODevice *vdev, 
uint8_t *config)
 struct virtio_net_config netcfg;
 
 stw_p(netcfg.status, n-status);
+stw_p(netcfg.max_virtqueue_pairs, n-max_queues);
 memcpy(netcfg.mac, n-mac, ETH_ALEN);
 memcpy(config, netcfg, sizeof(netcfg));
 }
@@ -116,31 +126,33 @@ static bool virtio_net_started(VirtIONet *n, uint8_t 
status)
 (n-status  VIRTIO_NET_S_LINK_UP)  n-vdev.vm_running;
 }
 
-static void virtio_net_vhost_status(VirtIONet *n, uint8_t status)
+static void virtio_net_vhost_status(VirtIONet *n, int queue_index,
+uint8_t status)
 {
-VirtIONetQueue *q = n-vq;
+NetClientState *nc = qemu_get_subqueue(n-nic, queue_index);
+VirtIONetQueue *q = n-vqs[queue_index];
 
-if (!qemu_get_queue(n-nic)-peer) {
+if (!nc-peer) {
 return;
 }
-if (qemu_get_queue(n-nic)-peer-info-type != 
NET_CLIENT_OPTIONS_KIND_TAP) {
+if (nc-peer-info-type != NET_CLIENT_OPTIONS_KIND_TAP) {
 return;
 }
 
-if (!tap_get_vhost_net(qemu_get_queue(n-nic)-peer)) {
+if (!tap_get_vhost_net(nc-peer)) {
 return;
 }
-if (!!q-vhost_started == virtio_net_started(n, status) 
-  !qemu_get_queue(n-nic)-peer-link_down) {
+if (!!q-vhost_started ==
+(virtio_net_started(n, status)  !nc-peer-link_down)) {
 return;
 }
 if (!q-vhost_started) {
 int r;
-if (!vhost_net_query(tap_get_vhost_net(qemu_get_queue(n-nic)-peer), 
n-vdev)) {
+if (!vhost_net_query(tap_get_vhost_net(nc-peer), n-vdev)) {
 return;
 }
-r = vhost_net_start(tap_get_vhost_net(qemu_get_queue(n-nic)-peer),
-n-vdev, 0);
+r = vhost_net_start(tap_get_vhost_net(nc-peer), n-vdev,
+queue_index * 2);
 if (r  0) {
 error_report(unable to start vhost net: %d: 
  falling back on userspace virtio, -r);
@@ -148,7 +160,7 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t 
status)
 q-vhost_started = 1;
 }
 } else {
-vhost_net_stop(tap_get_vhost_net(qemu_get_queue(n-nic)-peer), 
n-vdev);
+vhost_net_stop(tap_get_vhost_net(nc-peer), n-vdev);
 q-vhost_started = 0;
 }
 }
@@ -156,26 +168,35 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t 
status)
 static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
 {
 VirtIONet *n = to_virtio_net(vdev);
-VirtIONetQueue *q = n-vq;
+int i;
 
-virtio_net_vhost_status(n, status);
+for (i = 0; i  n-max_queues; i++) {
+VirtIONetQueue *q = n-vqs[i];
+uint8_t queue_status = status;
 
-if (!q-tx_waiting) {
-return;
-}
+if ((!n-multiqueue  i != 0) || i = n-curr_queues) {
+queue_status = 0;
+}
 
-if (virtio_net_started(n, status)  !q-vhost_started) {
-if (q-tx_timer) {
-qemu_mod_timer(q-tx_timer,
-   qemu_get_clock_ns(vm_clock) + n-tx_timeout);
-} else {
-qemu_bh_schedule(q-tx_bh);
+virtio_net_vhost_status(n, i, queue_status);
+
+if (!q-tx_waiting) {
+continue;
 }
-} else {
-if (q-tx_timer) {
-qemu_del_timer(q-tx_timer);
+
+if (virtio_net_started(n, status)  !q-vhost_started) {
+if (q-tx_timer) {
+qemu_mod_timer(q-tx_timer,
+   qemu_get_clock_ns(vm_clock) + n-tx_timeout);
+} else {
+

[PATCH 11/12] virtio-net: migration support for multiqueue

2012-12-28 Thread Jason Wang
This patch add migration support for multiqueue virtio-net. The version were
bumped to 12.

Signed-off-by: Jason Wang jasow...@redhat.com
---
 hw/virtio-net.c |   45 +++--
 1 files changed, 35 insertions(+), 10 deletions(-)

diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index aaeef1b..ca4b804 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -21,7 +21,7 @@
 #include virtio-net.h
 #include vhost_net.h
 
-#define VIRTIO_NET_VM_VERSION11
+#define VIRTIO_NET_VM_VERSION12
 
 #define MAC_TABLE_ENTRIES64
 #define MAX_VLAN(1  12)   /* Per 802.1Q definition */
@@ -1058,16 +1058,18 @@ static void virtio_net_set_multiqueue(VirtIONet *n, int 
multiqueue, int ctrl)
 
 static void virtio_net_save(QEMUFile *f, void *opaque)
 {
+int i;
 VirtIONet *n = opaque;
-VirtIONetQueue *q = n-vqs[0];
 
-/* At this point, backend must be stopped, otherwise
- * it might keep writing to memory. */
-assert(!q-vhost_started);
+for (i = 0; i  n-max_queues; i++) {
+/* At this point, backend must be stopped, otherwise
+ * it might keep writing to memory. */
+assert(!n-vqs[i].vhost_started);
+}
 virtio_save(n-vdev, f);
 
 qemu_put_buffer(f, n-mac, ETH_ALEN);
-qemu_put_be32(f, q-tx_waiting);
+qemu_put_be32(f, n-vqs[0].tx_waiting);
 qemu_put_be32(f, n-mergeable_rx_bufs);
 qemu_put_be16(f, n-status);
 qemu_put_byte(f, n-promisc);
@@ -1083,13 +1085,17 @@ static void virtio_net_save(QEMUFile *f, void *opaque)
 qemu_put_byte(f, n-nouni);
 qemu_put_byte(f, n-nobcast);
 qemu_put_byte(f, n-has_ufo);
+qemu_put_be16(f, n-max_queues);
+qemu_put_be16(f, n-curr_queues);
+for (i = 1; i  n-curr_queues; i++) {
+qemu_put_be32(f, n-vqs[i].tx_waiting);
+}
 }
 
 static int virtio_net_load(QEMUFile *f, void *opaque, int version_id)
 {
 VirtIONet *n = opaque;
-VirtIONetQueue *q = n-vqs[0];
-int ret, i;
+int ret, i, link_down;
 
 if (version_id  2 || version_id  VIRTIO_NET_VM_VERSION)
 return -EINVAL;
@@ -1100,7 +1106,7 @@ static int virtio_net_load(QEMUFile *f, void *opaque, int 
version_id)
 }
 
 qemu_get_buffer(f, n-mac, ETH_ALEN);
-q-tx_waiting = qemu_get_be32(f);
+n-vqs[0].tx_waiting = qemu_get_be32(f);
 
 virtio_net_set_mrg_rx_bufs(n, qemu_get_be32(f));
 
@@ -1170,6 +1176,22 @@ static int virtio_net_load(QEMUFile *f, void *opaque, 
int version_id)
 }
 }
 
+if (version_id = 12) {
+if (n-max_queues != qemu_get_be16(f)) {
+error_report(virtio-net: different max_queues );
+return -1;
+}
+
+n-curr_queues = qemu_get_be16(f);
+for (i = 1; i  n-curr_queues; i++) {
+n-vqs[i].tx_waiting = qemu_get_be32(f);
+}
+}
+
+virtio_net_set_queues(n);
+/* Must do this again, since we may have more than one active queues. */
+virtio_net_set_status(n-vdev, n-status);
+
 /* Find the first multicast entry in the saved MAC filter */
 for (i = 0; i  n-mac_table.in_use; i++) {
 if (n-mac_table.macs[i * ETH_ALEN]  1) {
@@ -1180,7 +1202,10 @@ static int virtio_net_load(QEMUFile *f, void *opaque, 
int version_id)
 
 /* nc.link_down can't be migrated, so infer link_down according
  * to link status bit in n-status */
-qemu_get_queue(n-nic)-link_down = (n-status  VIRTIO_NET_S_LINK_UP) == 
0;
+link_down = (n-status  VIRTIO_NET_S_LINK_UP) == 0;
+for (i = 0; i  n-max_queues; i++) {
+qemu_get_subqueue(n-nic, i)-link_down = link_down;
+}
 
 return 0;
 }
-- 
1.7.1

--
To unsubscribe from this list: send the line unsubscribe kvm in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 12/12] virtio-net: compat multiqueue support

2012-12-28 Thread Jason Wang
Disable multiqueue support for pre 1.4.

Signed-off-by: Jason Wang jasow...@redhat.com
---
 hw/pc_piix.c |4 
 1 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 19e342a..0145370 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -295,6 +295,10 @@ static QEMUMachine pc_machine_v1_4 = {
 .driver   = usb-tablet,\
 .property = usb_version,\
 .value= stringify(1),\
+},{ \
+.driver   = virtio-net-pci, \
+.property = mq, \
+.value= off, \
 }
 
 static QEMUMachine pc_machine_v1_3 = {
-- 
1.7.1

--
To unsubscribe from this list: send the line unsubscribe kvm in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 07/12] virtio: introduce virtio_queue_del()

2012-12-28 Thread Jason Wang
Some device (such as virtio-net) needs the ability to destroy or re-order the
virtqueues, this patch adds a helper to do this.

Signed-off-by: Jason Wang jasowang
---
 hw/virtio.c |9 +
 hw/virtio.h |2 ++
 2 files changed, 11 insertions(+), 0 deletions(-)

diff --git a/hw/virtio.c b/hw/virtio.c
index f40a8c5..bc3c9c3 100644
--- a/hw/virtio.c
+++ b/hw/virtio.c
@@ -700,6 +700,15 @@ VirtQueue *virtio_add_queue(VirtIODevice *vdev, int 
queue_size,
 return vdev-vq[i];
 }
 
+void virtio_del_queue(VirtIODevice *vdev, int n)
+{
+if (n  0 || n = VIRTIO_PCI_QUEUE_MAX) {
+abort();
+}
+
+vdev-vq[n].vring.num = 0;
+}
+
 void virtio_irq(VirtQueue *vq)
 {
 trace_virtio_irq(vq);
diff --git a/hw/virtio.h b/hw/virtio.h
index 7c17f7b..f6cb0f9 100644
--- a/hw/virtio.h
+++ b/hw/virtio.h
@@ -138,6 +138,8 @@ VirtQueue *virtio_add_queue(VirtIODevice *vdev, int 
queue_size,
 void (*handle_output)(VirtIODevice *,
   VirtQueue *));
 
+void virtio_del_queue(VirtIODevice *vdev, int n);
+
 void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem,
 unsigned int len);
 void virtqueue_flush(VirtQueue *vq, unsigned int count);
-- 
1.7.1

--
To unsubscribe from this list: send the line unsubscribe kvm in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Re: [Qemu-devel] [PATCH 10/12] virtio-net: multiqueue support

2012-12-28 Thread Blue Swirl
On Fri, Dec 28, 2012 at 10:32 AM, Jason Wang jasow...@redhat.com wrote:
 This patch implements both userspace and vhost support for multiple queue
 virtio-net (VIRTIO_NET_F_MQ). This is done by introducing an array of
 VirtIONetQueue to VirtIONet.

 Signed-off-by: Jason Wang jasow...@redhat.com
 ---
  hw/virtio-net.c |  318 
 ++-
  hw/virtio-net.h |   27 +-
  2 files changed, 271 insertions(+), 74 deletions(-)

 diff --git a/hw/virtio-net.c b/hw/virtio-net.c
 index c6f0915..aaeef1b 100644
 --- a/hw/virtio-net.c
 +++ b/hw/virtio-net.c
 @@ -45,7 +45,7 @@ typedef struct VirtIONet
  VirtIODevice vdev;
  uint8_t mac[ETH_ALEN];
  uint16_t status;
 -VirtIONetQueue vq;
 +VirtIONetQueue vqs[MAX_QUEUE_NUM];
  VirtQueue *ctrl_vq;
  NICState *nic;
  uint32_t tx_timeout;
 @@ -70,14 +70,23 @@ typedef struct VirtIONet
  } mac_table;
  uint32_t *vlans;
  DeviceState *qdev;
 +int multiqueue;
 +uint16_t max_queues;
 +uint16_t curr_queues;
  } VirtIONet;

 -static VirtIONetQueue *virtio_net_get_queue(NetClientState *nc)
 +static VirtIONetQueue *virtio_net_get_subqueue(NetClientState *nc)
  {
  VirtIONet *n = qemu_get_nic_opaque(nc);

 -return n-vq;
 +return n-vqs[nc-queue_index];
  }
 +
 +static int vq2q(int queue_index)
 +{
 +return queue_index / 2;
 +}
 +
  /* TODO
   * - we could suppress RX interrupt if we were so inclined.
   */
 @@ -93,6 +102,7 @@ static void virtio_net_get_config(VirtIODevice *vdev, 
 uint8_t *config)
  struct virtio_net_config netcfg;

  stw_p(netcfg.status, n-status);
 +stw_p(netcfg.max_virtqueue_pairs, n-max_queues);
  memcpy(netcfg.mac, n-mac, ETH_ALEN);
  memcpy(config, netcfg, sizeof(netcfg));
  }
 @@ -116,31 +126,33 @@ static bool virtio_net_started(VirtIONet *n, uint8_t 
 status)
  (n-status  VIRTIO_NET_S_LINK_UP)  n-vdev.vm_running;
  }

 -static void virtio_net_vhost_status(VirtIONet *n, uint8_t status)
 +static void virtio_net_vhost_status(VirtIONet *n, int queue_index,
 +uint8_t status)
  {
 -VirtIONetQueue *q = n-vq;
 +NetClientState *nc = qemu_get_subqueue(n-nic, queue_index);
 +VirtIONetQueue *q = n-vqs[queue_index];

 -if (!qemu_get_queue(n-nic)-peer) {
 +if (!nc-peer) {
  return;
  }
 -if (qemu_get_queue(n-nic)-peer-info-type != 
 NET_CLIENT_OPTIONS_KIND_TAP) {
 +if (nc-peer-info-type != NET_CLIENT_OPTIONS_KIND_TAP) {
  return;
  }

 -if (!tap_get_vhost_net(qemu_get_queue(n-nic)-peer)) {
 +if (!tap_get_vhost_net(nc-peer)) {
  return;
  }
 -if (!!q-vhost_started == virtio_net_started(n, status) 
 -  !qemu_get_queue(n-nic)-peer-link_down) {
 +if (!!q-vhost_started ==
 +(virtio_net_started(n, status)  !nc-peer-link_down)) {
  return;
  }
  if (!q-vhost_started) {
  int r;
 -if 
 (!vhost_net_query(tap_get_vhost_net(qemu_get_queue(n-nic)-peer), n-vdev)) 
 {
 +if (!vhost_net_query(tap_get_vhost_net(nc-peer), n-vdev)) {
  return;
  }
 -r = vhost_net_start(tap_get_vhost_net(qemu_get_queue(n-nic)-peer),
 -n-vdev, 0);
 +r = vhost_net_start(tap_get_vhost_net(nc-peer), n-vdev,
 +queue_index * 2);
  if (r  0) {
  error_report(unable to start vhost net: %d: 
   falling back on userspace virtio, -r);
 @@ -148,7 +160,7 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t 
 status)
  q-vhost_started = 1;
  }
  } else {
 -vhost_net_stop(tap_get_vhost_net(qemu_get_queue(n-nic)-peer), 
 n-vdev);
 +vhost_net_stop(tap_get_vhost_net(nc-peer), n-vdev);
  q-vhost_started = 0;
  }
  }
 @@ -156,26 +168,35 @@ static void virtio_net_vhost_status(VirtIONet *n, 
 uint8_t status)
  static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
  {
  VirtIONet *n = to_virtio_net(vdev);
 -VirtIONetQueue *q = n-vq;
 +int i;

 -virtio_net_vhost_status(n, status);
 +for (i = 0; i  n-max_queues; i++) {
 +VirtIONetQueue *q = n-vqs[i];
 +uint8_t queue_status = status;

 -if (!q-tx_waiting) {
 -return;
 -}
 +if ((!n-multiqueue  i != 0) || i = n-curr_queues) {
 +queue_status = 0;
 +}

 -if (virtio_net_started(n, status)  !q-vhost_started) {
 -if (q-tx_timer) {
 -qemu_mod_timer(q-tx_timer,
 -   qemu_get_clock_ns(vm_clock) + n-tx_timeout);
 -} else {
 -qemu_bh_schedule(q-tx_bh);
 +virtio_net_vhost_status(n, i, queue_status);
 +
 +if (!q-tx_waiting) {
 +continue;
  }
 -} else {
 -if (q-tx_timer) {
 -qemu_del_timer(q-tx_timer);
 +
 +if (virtio_net_started(n, status)  

Re: [Qemu-devel] [PATCH 05/12] net: multiqueue support

2012-12-28 Thread Blue Swirl
On Fri, Dec 28, 2012 at 10:31 AM, Jason Wang jasow...@redhat.com wrote:
 This patch adds basic multiqueue support for qemu. The idea is simple, an 
 array
 of NetClientStates were introduced in NICState, parse_netdev() were extended 
 to
 find and match all NetClientStates belongs to the backend and place their
 pointers in NICConf. Then qemu_new_nic can setup a N:N mapping between 
 NICStates
 that belongs to a nic and NICStates belongs to the netdev. After this, each
 peers of a NICStaet were abstracted as a queue.

 To adapt this change, set_link/netdev_del command will find all the
 NetClientStates of a nic or a netdev, and change all their state in one run.

 Signed-off-by: Jason Wang jasow...@redhat.com
 ---
  hw/dp8393x.c |2 +-
  hw/mcf_fec.c |2 +-
  hw/qdev-properties.c |   46 +++--
  hw/qdev-properties.h |6 +-
  net.c|  172 
 +-
  net.h|   27 +++-
  6 files changed, 195 insertions(+), 60 deletions(-)

 diff --git a/hw/dp8393x.c b/hw/dp8393x.c
 index 8f20a4a..fad0837 100644
 --- a/hw/dp8393x.c
 +++ b/hw/dp8393x.c
 @@ -899,7 +899,7 @@ void dp83932_init(NICInfo *nd, hwaddr base, int it_shift,
  s-regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */

  s-conf.macaddr = nd-macaddr;
 -s-conf.peer = nd-netdev;
 +s-conf.peers.ncs[0] = nd-netdev;

  s-nic = qemu_new_nic(net_dp83932_info, s-conf, nd-model, nd-name, 
 s);

 diff --git a/hw/mcf_fec.c b/hw/mcf_fec.c
 index 7fc89b5..c298bec 100644
 --- a/hw/mcf_fec.c
 +++ b/hw/mcf_fec.c
 @@ -472,7 +472,7 @@ void mcf_fec_init(MemoryRegion *sysmem, NICInfo *nd,
  memory_region_add_subregion(sysmem, base, s-iomem);

  s-conf.macaddr = nd-macaddr;
 -s-conf.peer = nd-netdev;
 +s-conf.peers[0] = nd-netdev;

  s-nic = qemu_new_nic(net_mcf_fec_info, s-conf, nd-model, nd-name, 
 s);

 diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c
 index 81d901c..6e45def 100644
 --- a/hw/qdev-properties.c
 +++ b/hw/qdev-properties.c
 @@ -585,16 +585,47 @@ PropertyInfo qdev_prop_chr = {

  static int parse_netdev(DeviceState *dev, const char *str, void **ptr)
  {
 -NetClientState *netdev = qemu_find_netdev(str);
 +NICPeers *peers_ptr = (NICPeers *)ptr;
 +NICConf *conf = container_of(peers_ptr, NICConf, peers);
 +NetClientState **ncs = peers_ptr-ncs;
 +NetClientState *peers[MAX_QUEUE_NUM];
 +int queues, i = 0;
 +int ret;

 -if (netdev == NULL) {
 -return -ENOENT;
 +queues = qemu_find_net_clients_except(str, peers,
 +  NET_CLIENT_OPTIONS_KIND_NIC,
 +  MAX_QUEUE_NUM);
 +if (queues == 0) {
 +ret = -ENOENT;
 +goto err;
  }
 -if (netdev-peer) {
 -return -EEXIST;
 +
 +if (queues  MAX_QUEUE_NUM) {
 +ret = -E2BIG;
 +goto err;
 +}
 +
 +for (i = 0; i  queues; i++) {
 +if (peers[i] == NULL) {
 +ret = -ENOENT;
 +goto err;
 +}
 +
 +if (peers[i]-peer) {
 +ret = -EEXIST;
 +goto err;
 +}
 +
 +ncs[i] = peers[i];
 +ncs[i]-queue_index = i;
  }
 -*ptr = netdev;
 +
 +conf-queues = queues;
 +
  return 0;
 +
 +err:
 +return ret;
  }

  static const char *print_netdev(void *ptr)
 @@ -661,7 +692,8 @@ static void set_vlan(Object *obj, Visitor *v, void 
 *opaque,
  {
  DeviceState *dev = DEVICE(obj);
  Property *prop = opaque;
 -NetClientState **ptr = qdev_get_prop_ptr(dev, prop);
 +NICPeers *peers_ptr = qdev_get_prop_ptr(dev, prop);
 +NetClientState **ptr = peers_ptr-ncs[0];
  Error *local_err = NULL;
  int32_t id;
  NetClientState *hubport;
 diff --git a/hw/qdev-properties.h b/hw/qdev-properties.h
 index 5b046ab..2d90848 100644
 --- a/hw/qdev-properties.h
 +++ b/hw/qdev-properties.h
 @@ -31,7 +31,7 @@ extern PropertyInfo qdev_prop_pci_host_devaddr;
  .name  = (_name),\
  .info  = (_prop),   \
  .offset= offsetof(_state, _field)\
 -+ type_check(_type,typeof_field(_state, _field)),\
 ++ type_check(_type, typeof_field(_state, _field)),   \
  }
  #define DEFINE_PROP_DEFAULT(_name, _state, _field, _defval, _prop, _type) { \
  .name  = (_name),   \
 @@ -77,9 +77,9 @@ extern PropertyInfo qdev_prop_pci_host_devaddr;
  #define DEFINE_PROP_STRING(_n, _s, _f) \
  DEFINE_PROP(_n, _s, _f, qdev_prop_string, char*)
  #define DEFINE_PROP_NETDEV(_n, _s, _f) \
 -DEFINE_PROP(_n, _s, _f, qdev_prop_netdev, NetClientState*)
 +DEFINE_PROP(_n, _s, _f, qdev_prop_netdev, NICPeers)
  #define DEFINE_PROP_VLAN(_n, _s, _f) \
 -DEFINE_PROP(_n, _s, _f, qdev_prop_vlan, 

[PATCH 2/2] target-i386: kvm: enable all supported KVM features for -cpu host

2012-12-28 Thread Eduardo Habkost
When using -cpu host, we don't need to use the kvm_default_features
variable, as the user is explicitly asking QEMU to enable all feature
supported by the host.

This changes the kvm_cpu_fill_host() code to use GET_SUPPORTED_CPUID to
initialize the kvm_features field, so we get all host KVM features
enabled.

This will also allow use to properly check/enforce KVM features inside
kvm_check_features_against_host() later. For example, we will be able to
make this:

  $ qemu-system-x86_64 -cpu ...,+kvm_pv_eoi,enforce

refuse to start if kvm_pv_eoi is not supported by the host (after we fix
kvm_check_features_against_host() to check KVM flags as well).

Signed-off-by: Eduardo Habkost ehabk...@redhat.com
---
 target-i386/cpu.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 6e2d32d..76f19f0 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -900,6 +900,8 @@ static void kvm_cpu_fill_host(x86_def_t *x86_cpu_def)
 /* Other KVM-specific feature fields: */
 x86_cpu_def-svm_features =
 kvm_arch_get_supported_cpuid(s, 0x800A, 0, R_EDX);
+x86_cpu_def-kvm_features =
+kvm_arch_get_supported_cpuid(s, KVM_CPUID_FEATURES, 0, R_EAX);
 
 #endif /* CONFIG_KVM */
 }
-- 
1.7.11.7

--
To unsubscribe from this list: send the line unsubscribe kvm in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 0/2] Fixes for -cpu host KVM/SVM feature initialization

2012-12-28 Thread Eduardo Habkost
This series has two very similar fixes for feature initizliation for -cpu
host. This should allow us to make the check/enforce code check for host
support of KVM and SVM features, later.

Eduardo Habkost (2):
  target-i386: kvm: -cpu host: use GET_SUPPORTED_CPUID for SVM features
  target-i386: kvm: enable all supported KVM features for -cpu host

 target-i386/cpu.c | 13 ++---
 1 file changed, 6 insertions(+), 7 deletions(-)

-- 
1.7.11.7

--
To unsubscribe from this list: send the line unsubscribe kvm in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[PATCH 1/2] target-i386: kvm: -cpu host: use GET_SUPPORTED_CPUID for SVM features

2012-12-28 Thread Eduardo Habkost
The existing -cpu host code simply set every bit inside svm_features
(initializing it to -1), and that makes it impossible to make the
enforce/check options work properly when the user asks for SVM features
explicitly in the command-line.

So, instead of initializing svm_features to -1, use GET_SUPPORTED_CPUID
to fill only the bits that are supported by the host (just like we do
for all other CPUID feature words inside kvm_cpu_fill_host()).

This will keep the existing behavior (as filter_features_for_kvm()
already uses GET_SUPPORTED_CPUID to filter svm_features), but will allow
us to properly check for KVM features inside
kvm_check_features_against_host() later.

For example, we will be able to make this:

  $ qemu-system-x86_64 -cpu ...,+pfthreshold,enforce

refuse to start if the SVM pfthreshold feature is not supported by the
host (after we fix kvm_check_features_against_host() to check SVM flags
as well).

Signed-off-by: Eduardo Habkost ehabk...@redhat.com
---
 target-i386/cpu.c | 11 ---
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 3cd1cee..6e2d32d 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -897,13 +897,10 @@ static void kvm_cpu_fill_host(x86_def_t *x86_cpu_def)
 }
 }
 
-/*
- * Every SVM feature requires emulation support in KVM - so we can't just
- * read the host features here. KVM might even support SVM features not
- * available on the host hardware. Just set all bits and mask out the
- * unsupported ones later.
- */
-x86_cpu_def-svm_features = -1;
+/* Other KVM-specific feature fields: */
+x86_cpu_def-svm_features =
+kvm_arch_get_supported_cpuid(s, 0x800A, 0, R_EDX);
+
 #endif /* CONFIG_KVM */
 }
 
-- 
1.7.11.7

--
To unsubscribe from this list: send the line unsubscribe kvm in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html