[pve-devel] [PATCH qemu-server 12/13] arm: pci addressing, keyboard and ehci controller

Wolfgang Bumiller w.bumiller at proxmox.com
Wed Oct 24 10:56:48 CEST 2018


On arm we start off with a pcie bridge pcie.0. We need a
keyboard in addition to the tablet device, and we need to
connect both to an 'ehci' controller.

To do all this, we also pass the $arch variable through a
whole lot of function calls to ultimately also adapt the
hotplug code to take care of the new keyboard device.

Signed-off-by: Wolfgang Bumiller <w.bumiller at proxmox.com>
---
 PVE/QemuServer.pm     | 134 ++++++++++++++++++++++++++++++--------------------
 PVE/QemuServer/PCI.pm |  16 ++++--
 PVE/QemuServer/USB.pm |  11 +++--
 3 files changed, 101 insertions(+), 60 deletions(-)

diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index ceba4b2..f77417f 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -1661,24 +1661,37 @@ sub machine_type_is_q35 {
 }
 
 sub print_tabletdevice_full {
-    my ($conf) = @_;
+    my ($conf, $arch) = @_;
 
     my $q35 = machine_type_is_q35($conf);
 
     # we use uhci for old VMs because tablet driver was buggy in older qemu
-    my $usbbus = $q35 ? "ehci" : "uhci";
+    my $usbbus;
+    if (machine_type_is_q35($conf) || $arch eq 'arm64') {
+	$usbbus = 'ehci';
+    } else {
+	$usbbus = 'uhci';
+    }
 
     return "usb-tablet,id=tablet,bus=$usbbus.0,port=1";
 }
 
+sub print_keyboarddevice_full {
+    my ($conf, $arch, $machine) = @_;
+
+    return undef if $arch ne 'arm64';
+
+    return "usb-kbd,id=keyboard,bus=ehci.0,port=2";
+}
+
 sub print_drivedevice_full {
-    my ($storecfg, $conf, $vmid, $drive, $bridges) = @_;
+    my ($storecfg, $conf, $vmid, $drive, $bridges, $arch, $base_machine) = @_;
 
     my $device = '';
     my $maxdev = 0;
 
     if ($drive->{interface} eq 'virtio') {
-	my $pciaddr = print_pci_addr("$drive->{interface}$drive->{index}", $bridges);
+	my $pciaddr = print_pci_addr("$drive->{interface}$drive->{index}", $bridges, $arch, $base_machine);
 	$device = "virtio-blk-pci,drive=drive-$drive->{interface}$drive->{index},id=$drive->{interface}$drive->{index}$pciaddr";
 	$device .= ",iothread=iothread-$drive->{interface}$drive->{index}" if $drive->{iothread};
     } elsif ($drive->{interface} eq 'scsi') {
@@ -1855,7 +1868,7 @@ sub print_drive_full {
 }
 
 sub print_netdevice_full {
-    my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files) = @_;
+    my ($vmid, $conf, $net, $netid, $bridges, $use_old_bios_files, $arch, $base_machine) = @_;
 
     my $bootorder = $conf->{boot} || $confdesc->{boot}->{default};
 
@@ -1864,7 +1877,7 @@ sub print_netdevice_full {
          $device = 'virtio-net-pci';
      };
 
-    my $pciaddr = print_pci_addr("$netid", $bridges);
+    my $pciaddr = print_pci_addr("$netid", $bridges, $arch, $base_machine);
     my $tmpstr = "$device,mac=$net->{macaddr},netdev=$netid$pciaddr,id=$netid";
     if ($net->{queues} && $net->{queues} > 1 && $net->{model} eq 'virtio'){
 	#Consider we have N queues, the number of vectors needed is 2*N + 2 (plus one config interrupt and control vq)
@@ -1893,7 +1906,7 @@ sub print_netdevice_full {
 }
 
 sub print_netdev_full {
-    my ($vmid, $conf, $net, $netid, $hotplug) = @_;
+    my ($vmid, $conf, $arch, $net, $netid, $hotplug) = @_;
 
     my $i = '';
     if ($netid =~ m/^net(\d+)$/) {
@@ -3374,7 +3387,7 @@ sub config_to_command {
 
 
     # add usb controllers
-    my @usbcontrollers = PVE::QemuServer::USB::get_usb_controllers($conf, $bridges, $q35, $usbdesc->{format}, $MAX_USB_DEVICES);
+    my @usbcontrollers = PVE::QemuServer::USB::get_usb_controllers($conf, $bridges, $arch, $base_machine, $usbdesc->{format}, $MAX_USB_DEVICES);
     push @$devices, @usbcontrollers if @usbcontrollers;
     my $vga = $conf->{vga};
 
@@ -3399,7 +3412,11 @@ sub config_to_command {
 	$tablet = 0 if $vga =~ m/^serial\d+$/; # disable if we use serial terminal (no vga card)
     }
 
-    push @$devices, '-device', print_tabletdevice_full($conf) if $tablet;
+    if ($tablet) {
+	push @$devices, '-device', print_tabletdevice_full($conf, $arch) if $tablet;
+	my $kbd = print_keyboarddevice_full($conf, $arch);
+	push @$devices, '-device', $kbd if defined($kbd);
+    }
 
     my $kvm_off = 0;
     my $gpu_passthrough;
@@ -3414,7 +3431,7 @@ sub config_to_command {
 	    die "q35 machine model is not enabled" if !$q35;
 	    $pciaddr = print_pcie_addr("hostpci$i");
 	}else{
-	    $pciaddr = print_pci_addr("hostpci$i", $bridges);
+	    $pciaddr = print_pci_addr("hostpci$i", $bridges, $arch, $base_machine);
 	}
 
 	my $rombar = defined($d->{rombar}) && !$d->{rombar} ? ',rombar=0' : '';
@@ -3599,7 +3616,7 @@ sub config_to_command {
 
     if (parse_guest_agent($conf)->{enabled}) {
 	my $qgasocket = qmp_socket($vmid, 1);
-	my $pciaddr = print_pci_addr("qga0", $bridges);
+	my $pciaddr = print_pci_addr("qga0", $bridges, $arch, $base_machine);
 	push @$devices, '-chardev', "socket,path=$qgasocket,server,nowait,id=qga0";
 	push @$devices, '-device', "virtio-serial,id=qga0$pciaddr";
 	push @$devices, '-device', 'virtserialport,chardev=qga0,name=org.qemu.guest_agent.0';
@@ -3611,7 +3628,7 @@ sub config_to_command {
 	if ($qxlnum > 1) {
 	    if ($winversion){
 		for(my $i = 1; $i < $qxlnum; $i++){
-		    my $pciaddr = print_pci_addr("vga$i", $bridges);
+		    my $pciaddr = print_pci_addr("vga$i", $bridges, $arch, $base_machine);
 		    push @$devices, '-device', "qxl,id=vga$i,ram_size=67108864,vram_size=33554432$pciaddr";
 		}
 	    } else {
@@ -3621,7 +3638,7 @@ sub config_to_command {
 	    }
 	}
 
-	my $pciaddr = print_pci_addr("spice", $bridges);
+	my $pciaddr = print_pci_addr("spice", $bridges, $arch, $base_machine);
 
 	my $nodename = PVE::INotify::nodename();
 	my $pfamily = PVE::Tools::get_host_address_family($nodename);
@@ -3639,13 +3656,13 @@ sub config_to_command {
 
     # enable balloon by default, unless explicitly disabled
     if (!defined($conf->{balloon}) || $conf->{balloon}) {
-	$pciaddr = print_pci_addr("balloon0", $bridges);
+	$pciaddr = print_pci_addr("balloon0", $bridges, $arch, $base_machine);
 	push @$devices, '-device', "virtio-balloon-pci,id=balloon0$pciaddr";
     }
 
     if ($conf->{watchdog}) {
 	my $wdopts = parse_watchdog($conf->{watchdog});
-	$pciaddr = print_pci_addr("watchdog", $bridges);
+	$pciaddr = print_pci_addr("watchdog", $bridges, $arch, $base_machine);
 	my $watchdog = $wdopts->{model} || 'i6300esb';
 	push @$devices, '-device', "$watchdog$pciaddr";
 	push @$devices, '-watchdog-action', $wdopts->{action} if $wdopts->{action};
@@ -3693,7 +3710,7 @@ sub config_to_command {
 
 	    my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $drive);
 
-	    $pciaddr = print_pci_addr("$controller_prefix$controller", $bridges);
+	    $pciaddr = print_pci_addr("$controller_prefix$controller", $bridges, $arch, $base_machine);
 	    my $scsihw_type = $scsihw =~ m/^virtio-scsi-single/ ? "virtio-scsi-pci" : $scsihw;
 
 	    my $iothread = '';
@@ -3715,14 +3732,14 @@ sub config_to_command {
 
         if ($drive->{interface} eq 'sata') {
            my $controller = int($drive->{index} / $MAX_SATA_DISKS);
-           $pciaddr = print_pci_addr("ahci$controller", $bridges);
+           $pciaddr = print_pci_addr("ahci$controller", $bridges, $arch, $base_machine);
            push @$devices, '-device', "ahci,id=ahci$controller,multifunction=on$pciaddr" if !$ahcicontroller->{$controller};
            $ahcicontroller->{$controller}=1;
         }
 
 	my $drive_cmd = print_drive_full($storecfg, $vmid, $drive);
 	push @$devices, '-drive',$drive_cmd;
-	push @$devices, '-device', print_drivedevice_full($storecfg, $conf, $vmid, $drive, $bridges);
+	push @$devices, '-device', print_drivedevice_full($storecfg, $conf, $vmid, $drive, $bridges, $arch, $base_machine);
     });
 
     for (my $i = 0; $i < $MAX_NETS; $i++) {
@@ -3737,10 +3754,10 @@ sub config_to_command {
             $bootindex_hash->{n} += 1;
          }
 
-         my $netdevfull = print_netdev_full($vmid,$conf,$d,"net$i");
+         my $netdevfull = print_netdev_full($vmid, $conf, $arch, $d, "net$i");
          push @$devices, '-netdev', $netdevfull;
 
-         my $netdevicefull = print_netdevice_full($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files);
+         my $netdevicefull = print_netdevice_full($vmid, $conf, $d, "net$i", $bridges, $use_old_bios_files, $arch, $base_machine);
          push @$devices, '-device', $netdevicefull;
     }
 
@@ -3754,7 +3771,7 @@ sub config_to_command {
 	$bridges->{3} = 1 if $scsihw =~ m/^virtio-scsi-single/;
 
 	while (my ($k, $v) = each %$bridges) {
-	    $pciaddr = print_pci_addr("pci.$k");
+	    $pciaddr = print_pci_addr("pci.$k", undef, $arch, $base_machine);
 	    unshift @$devices, '-device', "pci-bridge,id=pci.$k,chassis_nr=$k$pciaddr" if $k > 0;
 	}
     }
@@ -3852,18 +3869,22 @@ sub vm_devices_list {
 }
 
 sub vm_deviceplug {
-    my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
+    my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $base_machine) = @_;
 
     my $q35 = machine_type_is_q35($conf);
 
     my $devices_list = vm_devices_list($vmid);
     return 1 if defined($devices_list->{$deviceid});
 
-    qemu_add_pci_bridge($storecfg, $conf, $vmid, $deviceid); # add PCI bridge if we need it for the device
+    qemu_add_pci_bridge($storecfg, $conf, $vmid, $deviceid, $arch, $base_machine); # add PCI bridge if we need it for the device
 
     if ($deviceid eq 'tablet') {
 
-	qemu_deviceadd($vmid, print_tabletdevice_full($conf));
+	qemu_deviceadd($vmid, print_tabletdevice_full($conf, $arch));
+
+    } elsif ($deviceid eq 'keyboard') {
+
+	qemu_deviceadd($vmid, print_keyboarddevice_full($conf, $arch));
 
     } elsif ($deviceid =~ m/^usb(\d+)$/) {
 
@@ -3878,7 +3899,7 @@ sub vm_deviceplug {
 	qemu_iothread_add($vmid, $deviceid, $device);
 
         qemu_driveadd($storecfg, $vmid, $device);
-        my $devicefull = print_drivedevice_full($storecfg, $conf, $vmid, $device);
+        my $devicefull = print_drivedevice_full($storecfg, $conf, $vmid, $device, $arch, $base_machine);
 
         qemu_deviceadd($vmid, $devicefull);
 	eval { qemu_deviceaddverify($vmid, $deviceid); };
@@ -3892,7 +3913,7 @@ sub vm_deviceplug {
 
 
         my $scsihw = defined($conf->{scsihw}) ? $conf->{scsihw} : "lsi";
-        my $pciaddr = print_pci_addr($deviceid);
+        my $pciaddr = print_pci_addr($deviceid, undef, $arch, $base_machine);
 	my $scsihw_type = $scsihw eq 'virtio-scsi-single' ? "virtio-scsi-pci" : $scsihw;
 
         my $devicefull = "$scsihw_type,id=$deviceid$pciaddr";
@@ -3911,10 +3932,10 @@ sub vm_deviceplug {
 
     } elsif ($deviceid =~ m/^(scsi)(\d+)$/) {
 
-        qemu_findorcreatescsihw($storecfg,$conf, $vmid, $device);
+        qemu_findorcreatescsihw($storecfg,$conf, $vmid, $device, $arch, $base_machine);
         qemu_driveadd($storecfg, $vmid, $device);
 
-	my $devicefull = print_drivedevice_full($storecfg, $conf, $vmid, $device);
+	my $devicefull = print_drivedevice_full($storecfg, $conf, $vmid, $device, $arch, $base_machine);
 	eval { qemu_deviceadd($vmid, $devicefull); };
 	if (my $err = $@) {
 	    eval { qemu_drivedel($vmid, $deviceid); };
@@ -3924,13 +3945,13 @@ sub vm_deviceplug {
 
     } elsif ($deviceid =~ m/^(net)(\d+)$/) {
 
-        return undef if !qemu_netdevadd($vmid, $conf, $device, $deviceid);
+        return undef if !qemu_netdevadd($vmid, $conf, $arch, $device, $deviceid);
 
         my $machine_type = PVE::QemuServer::qemu_machine_pxe($vmid, $conf); 
         my $use_old_bios_files = undef;
         ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files($machine_type);
 
-        my $netdevicefull = print_netdevice_full($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files);
+        my $netdevicefull = print_netdevice_full($vmid, $conf, $device, $deviceid, undef, $use_old_bios_files, $arch, $base_machine);
         qemu_deviceadd($vmid, $netdevicefull);
         eval { qemu_deviceaddverify($vmid, $deviceid); };
 	if (my $err = $@) {
@@ -3942,7 +3963,7 @@ sub vm_deviceplug {
     } elsif (!$q35 && $deviceid =~ m/^(pci\.)(\d+)$/) {
 
 	my $bridgeid = $2;
-	my $pciaddr = print_pci_addr($deviceid);
+	my $pciaddr = print_pci_addr($deviceid, undef, $arch, $base_machine);
 	my $devicefull = "pci-bridge,id=pci.$bridgeid,chassis_nr=$bridgeid$pciaddr";
 
 	qemu_deviceadd($vmid, $devicefull);
@@ -3964,7 +3985,7 @@ sub vm_deviceunplug {
 
     die "can't unplug bootdisk" if $conf->{bootdisk} && $conf->{bootdisk} eq $deviceid;
 
-    if ($deviceid eq 'tablet') {
+    if ($deviceid eq 'tablet' || $deviceid eq 'keyboard') {
 
 	qemu_devicedel($vmid, $deviceid);
 
@@ -4115,7 +4136,7 @@ sub qemu_devicedelverify {
 }
 
 sub qemu_findorcreatescsihw {
-    my ($storecfg, $conf, $vmid, $device) = @_;
+    my ($storecfg, $conf, $vmid, $device, $arch, $base_machine) = @_;
 
     my ($maxdev, $controller, $controller_prefix) = scsihw_infos($conf, $device);
 
@@ -4123,7 +4144,7 @@ sub qemu_findorcreatescsihw {
     my $devices_list = vm_devices_list($vmid);
 
     if(!defined($devices_list->{$scsihwid})) {
-	vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device);
+	vm_deviceplug($storecfg, $conf, $vmid, $scsihwid, $device, $arch, $base_machine);
     }
 
     return 1;
@@ -4159,13 +4180,13 @@ sub qemu_deletescsihw {
 }
 
 sub qemu_add_pci_bridge {
-    my ($storecfg, $conf, $vmid, $device) = @_;
+    my ($storecfg, $conf, $vmid, $device, $arch, $base_machine) = @_;
 
     my $bridges = {};
 
     my $bridgeid;
 
-    print_pci_addr($device, $bridges);
+    print_pci_addr($device, $bridges, $arch, $base_machine);
 
     while (my ($k, $v) = each %$bridges) {
 	$bridgeid = $k;
@@ -4176,7 +4197,7 @@ sub qemu_add_pci_bridge {
     my $devices_list = vm_devices_list($vmid);
 
     if (!defined($devices_list->{$bridge})) {
-	vm_deviceplug($storecfg, $conf, $vmid, $bridge);
+	vm_deviceplug($storecfg, $conf, $vmid, $bridge, $arch, $base_machine);
     }
 
     return 1;
@@ -4190,9 +4211,9 @@ sub qemu_set_link_status {
 }
 
 sub qemu_netdevadd {
-    my ($vmid, $conf, $device, $deviceid) = @_;
+    my ($vmid, $conf, $arch, $device, $deviceid) = @_;
 
-    my $netdev = print_netdev_full($vmid, $conf, $device, $deviceid, 1);
+    my $netdev = print_netdev_full($vmid, $conf, $arch, $device, $deviceid, 1);
     my %options =  split(/[=,]/, $netdev);
 
     vm_mon_cmd($vmid, "netdev_add",  %options);
@@ -4206,7 +4227,7 @@ sub qemu_netdevdel {
 }
 
 sub qemu_usb_hotplug {
-    my ($storecfg, $conf, $vmid, $deviceid, $device) = @_;
+    my ($storecfg, $conf, $vmid, $deviceid, $device, $arch, $base_machine) = @_;
 
     return if !$device;
 
@@ -4219,7 +4240,7 @@ sub qemu_usb_hotplug {
 	my $devicelist = vm_devices_list($vmid);
 
 	if (!$devicelist->{xhci}) {
-	    my $pciaddr = print_pci_addr("xhci");
+	    my $pciaddr = print_pci_addr("xhci", undef, $arch, $base_machine);
 	    qemu_deviceadd($vmid, "nec-usb-xhci,id=xhci$pciaddr");
 	}
     }
@@ -4227,7 +4248,7 @@ sub qemu_usb_hotplug {
     $d->{usb3} = $device->{usb3};
 
     # add the new one
-    vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d);
+    vm_deviceplug($storecfg, $conf, $vmid, $deviceid, $d, $arch, $base_machine);
 }
 
 sub qemu_cpu_hotplug {
@@ -4461,6 +4482,7 @@ sub vmconfig_hotplug_pending {
     my ($vmid, $conf, $storecfg, $selection, $errors) = @_;
 
     my $defaults = load_defaults();
+    my ($arch, $base_machine) = get_basic_machine_info($conf);
 
     # commit values which do not have any impact on running VM first
     # Note: those option cannot raise errors, we we do not care about
@@ -4496,9 +4518,12 @@ sub vmconfig_hotplug_pending {
 	    } elsif ($opt eq 'tablet') {
 		die "skip\n" if !$hotplug_features->{usb};
 		if ($defaults->{tablet}) {
-		    vm_deviceplug($storecfg, $conf, $vmid, $opt);
+		    vm_deviceplug($storecfg, $conf, $vmid, 'tablet', $arch, $base_machine);
+		    vm_deviceplug($storecfg, $conf, $vmid, 'keyboard', $arch, $base_machine)
+			if $arch eq 'arm64';
 		} else {
-		    vm_deviceunplug($vmid, $conf, $opt);
+		    vm_deviceunplug($vmid, $conf, 'tablet');
+		    vm_deviceunplug($vmid, $conf, 'keyboard') if $arch eq 'arm64';
 		}
 	    } elsif ($opt =~ m/^usb\d+/) {
 		die "skip\n";
@@ -4571,9 +4596,12 @@ sub vmconfig_hotplug_pending {
 	    } elsif ($opt eq 'tablet') {
 		die "skip\n" if !$hotplug_features->{usb};
 		if ($value == 1) {
-		    vm_deviceplug($storecfg, $conf, $vmid, $opt);
+		    vm_deviceplug($storecfg, $conf, $vmid, 'tablet', $arch, $base_machine);
+		    vm_deviceplug($storecfg, $conf, $vmid, 'keyboard', $arch, $base_machine)
+			if $arch eq 'arm64';
 		} elsif ($value == 0) {
-		    vm_deviceunplug($vmid, $conf, $opt);
+		    vm_deviceunplug($vmid, $conf, 'tablet');
+		    vm_deviceunplug($vmid, $conf, 'keyboard') if $arch eq 'arm64';
 		}
 	    } elsif ($opt =~ m/^usb\d+$/) {
 		die "skip\n";
@@ -4582,7 +4610,7 @@ sub vmconfig_hotplug_pending {
 		die "skip\n" if !$hotplug_features->{usb} || $value =~ m/spice/i;
 		my $d = eval { PVE::JSONSchema::parse_property_string($usbdesc->{format}, $value) };
 		die "skip\n" if !$d;
-		qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d);
+		qemu_usb_hotplug($storecfg, $conf, $vmid, $opt, $d, $arch, $base_machine);
 	    } elsif ($opt eq 'vcpus') {
 		die "skip\n" if !$hotplug_features->{cpu};
 		qemu_cpu_hotplug($vmid, $conf, $value);
@@ -4600,7 +4628,7 @@ sub vmconfig_hotplug_pending {
 	    } elsif ($opt =~ m/^net(\d+)$/) {
 		# some changes can be done without hotplug
 		vmconfig_update_net($storecfg, $conf, $hotplug_features->{network},
-				    $vmid, $opt, $value);
+				    $vmid, $opt, $value, $arch, $base_machine);
 	    } elsif (is_valid_drivename($opt)) {
 		# some changes can be done without hotplug
 		my $drive = parse_drive($opt, $value);
@@ -4608,7 +4636,7 @@ sub vmconfig_hotplug_pending {
 		    &$apply_pending_cloudinit($opt, $value);
 		}
 		vmconfig_update_disk($storecfg, $conf, $hotplug_features->{disk},
-				     $vmid, $opt, $value, 1);
+				     $vmid, $opt, $value, 1, $arch, $base_machine);
 	    } elsif ($opt =~ m/^memory$/) { #dimms
 		die "skip\n" if !$hotplug_features->{memory};
 		$value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
@@ -4737,7 +4765,7 @@ my $safe_string_ne = sub {
 };
 
 sub vmconfig_update_net {
-    my ($storecfg, $conf, $hotplug, $vmid, $opt, $value) = @_;
+    my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $arch, $base_machine) = @_;
 
     my $newnet = parse_net($value);
 
@@ -4778,14 +4806,14 @@ sub vmconfig_update_net {
     }
 
     if ($hotplug) {
-	vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet);
+	vm_deviceplug($storecfg, $conf, $vmid, $opt, $newnet, $arch, $base_machine);
     } else {
 	die "skip\n";
     }
 }
 
 sub vmconfig_update_disk {
-    my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force) = @_;
+    my ($storecfg, $conf, $hotplug, $vmid, $opt, $value, $force, $arch, $base_machine) = @_;
 
     # fixme: do we need force?
 
@@ -4886,7 +4914,7 @@ sub vmconfig_update_disk {
     die "skip\n" if !$hotplug || $opt =~ m/(ide|sata)(\d+)/;
     # hotplug new disks
     PVE::Storage::activate_volumes($storecfg, [$drive->{file}]) if $drive->{file} !~ m|^/dev/.+|;
-    vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive);
+    vm_deviceplug($storecfg, $conf, $vmid, $opt, $drive, $arch, $base_machine);
 }
 
 sub vm_start {
diff --git a/PVE/QemuServer/PCI.pm b/PVE/QemuServer/PCI.pm
index 0d9cf24..19043c0 100644
--- a/PVE/QemuServer/PCI.pm
+++ b/PVE/QemuServer/PCI.pm
@@ -9,7 +9,8 @@ print_pcie_addr
 
 my $devices = {
     piix3 => { bus => 0, addr => 1 },
-    #addr2 : first videocard
+    ehci => { bus => 0, addr => 1 }, # instead of piix3 on arm
+    vga => { bus => 0, addr => 2 }, #addr2 : first videocard
     balloon0 => { bus => 0, addr => 3 },
     watchdog => { bus => 0, addr => 4 },
     scsihw0 => { bus => 0, addr => 5 },
@@ -111,14 +112,23 @@ my $devices = {
 };
 
 sub print_pci_addr {
-    my ($id, $bridges) = @_;
+    my ($id, $bridges, $arch, $machine) = @_;
 
     my $res = '';
 
+    # We use the same bus slots on all hardware, so we need to check special
+    # cases here:
+    my $busname = 'pci';
+    if ($arch eq 'arm64' && $machine eq 'virt') {
+	die "arm64/virt cannot use IDE devices\n"
+	    if $id =~ /^ide/;
+	$busname = 'pcie';
+    }
+
     if (defined($devices->{$id}->{bus}) && defined($devices->{$id}->{addr})) {
 	   my $addr = sprintf("0x%x", $devices->{$id}->{addr});
 	   my $bus = $devices->{$id}->{bus};
-	   $res = ",bus=pci.$bus,addr=$addr";
+	   $res = ",bus=$busname.$bus,addr=$addr";
 	   $bridges->{$bus} = 1 if $bridges;
     }
     return $res;
diff --git a/PVE/QemuServer/USB.pm b/PVE/QemuServer/USB.pm
index 599641e..b26c617 100644
--- a/PVE/QemuServer/USB.pm
+++ b/PVE/QemuServer/USB.pm
@@ -34,17 +34,20 @@ sub parse_usb_device {
 }
 
 sub get_usb_controllers {
-    my ($conf, $bridges, $isq35, $format, $max_usb_devices) = @_;
+    my ($conf, $bridges, $arch, $machine, $format, $max_usb_devices) = @_;
 
     my $devices = [];
     my $pciaddr = "";
 
-    if ($isq35) {
+    if ($arch eq 'arm64') {
+        $pciaddr = print_pci_addr('ehci', $bridges, $arch, $machine);
+        push @$devices, '-device', "usb-ehci,id=ehci$pciaddr";
+    } elsif ($machine eq 'q35') {
 	# the q35 chipset support native usb2, so we enable usb controller
 	# by default for this machine type
         push @$devices, '-readconfig', '/usr/share/qemu-server/pve-q35.cfg';
     } else {
-        $pciaddr = print_pci_addr("piix3", $bridges);
+        $pciaddr = print_pci_addr("piix3", $bridges, $arch, $machine);
         push @$devices, '-device', "piix3-usb-uhci,id=uhci$pciaddr.0x2";
 
         my $use_usb2 = 0;
@@ -68,7 +71,7 @@ sub get_usb_controllers {
 	$use_usb3 = 1;
     }
 
-    $pciaddr = print_pci_addr("xhci", $bridges);
+    $pciaddr = print_pci_addr("xhci", $bridges, $arch, $machine);
     push @$devices, '-device', "nec-usb-xhci,id=xhci$pciaddr" if $use_usb3;
 
     return @$devices;
-- 
2.11.0





More information about the pve-devel mailing list