[trusty,1/1] x86, irq, pic: Probe for legacy PIC and set legacy_pic appropriately
diff mbox

Message ID 1408538794-18234-2-git-send-email-apw@canonical.com
State New
Headers show

Commit Message

Andy Whitcroft Aug. 20, 2014, 12:46 p.m. UTC
From: "K. Y. Srinivasan" <kys@microsoft.com>

The legacy PIC may or may not be available and we need a mechanism to
detect the existence of the legacy PIC that is applicable for all
hardware (both physical as well as virtual) currently supported by
Linux.

On Hyper-V, when our legacy firmware presented to the guests, emulates
the legacy PIC while when our EFI based firmware is presented we do
not emulate the PIC. To support Hyper-V EFI firmware, we had to set
the legacy_pic to the null_legacy_pic since we had to bypass PIC based
calibration in the early boot code. While, on the EFI firmware, we
know we don't emulate the legacy PIC, we need a generic mechanism to
detect the presence of the legacy PIC that is not based on boot time
state - this became apparent when we tried to get kexec to work on
Hyper-V EFI firmware.

This patch implements the proposal put forth by H. Peter Anvin
<hpa@linux.intel.com>: Write a known value to the PIC data port and
read it back. If the value read is the value written, we do have the
PIC, if not there is no PIC and we can safely set the legacy_pic to
null_legacy_pic. Since the read from an unconnected I/O port returns
0xff, we will use ~(1 << PIC_CASCADE_IR) (0xfb: mask all lines except
the cascade line) to probe for the existence of the PIC.

In version V1 of the patch, I had cleaned up the code based on comments from Peter.
In version V2 of the patch, I have addressed additional comments from Peter.
In version V3 of the patch, I have addressed Jan's comments (JBeulich@suse.com).
In version V4 of the patch, I have addressed additional comments from Peter.

Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Link: http://lkml.kernel.org/r/1397501029-29286-1-git-send-email-kys@microsoft.com
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>

(cherry picked from commit e179f6914152eca9b338e7d8445684062f560c55)
BugLink: http://bugs.launchpad.net/bugs/1317697
Signed-off-by: Andy Whitcroft <apw@canonical.com>
---
 arch/x86/kernel/cpu/mshyperv.c |  9 ---------
 arch/x86/kernel/i8259.c        | 20 +++++++++++++++++++-
 2 files changed, 19 insertions(+), 10 deletions(-)

Comments

Brad Figg Aug. 20, 2014, 5:44 p.m. UTC | #1
On 08/20/2014 05:46 AM, Andy Whitcroft wrote:
> From: "K. Y. Srinivasan" <kys@microsoft.com>
> 
> The legacy PIC may or may not be available and we need a mechanism to
> detect the existence of the legacy PIC that is applicable for all
> hardware (both physical as well as virtual) currently supported by
> Linux.
> 
> On Hyper-V, when our legacy firmware presented to the guests, emulates
> the legacy PIC while when our EFI based firmware is presented we do
> not emulate the PIC. To support Hyper-V EFI firmware, we had to set
> the legacy_pic to the null_legacy_pic since we had to bypass PIC based
> calibration in the early boot code. While, on the EFI firmware, we
> know we don't emulate the legacy PIC, we need a generic mechanism to
> detect the presence of the legacy PIC that is not based on boot time
> state - this became apparent when we tried to get kexec to work on
> Hyper-V EFI firmware.
> 
> This patch implements the proposal put forth by H. Peter Anvin
> <hpa@linux.intel.com>: Write a known value to the PIC data port and
> read it back. If the value read is the value written, we do have the
> PIC, if not there is no PIC and we can safely set the legacy_pic to
> null_legacy_pic. Since the read from an unconnected I/O port returns
> 0xff, we will use ~(1 << PIC_CASCADE_IR) (0xfb: mask all lines except
> the cascade line) to probe for the existence of the PIC.
> 
> In version V1 of the patch, I had cleaned up the code based on comments from Peter.
> In version V2 of the patch, I have addressed additional comments from Peter.
> In version V3 of the patch, I have addressed Jan's comments (JBeulich@suse.com).
> In version V4 of the patch, I have addressed additional comments from Peter.
> 
> Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
> Link: http://lkml.kernel.org/r/1397501029-29286-1-git-send-email-kys@microsoft.com
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
> 
> (cherry picked from commit e179f6914152eca9b338e7d8445684062f560c55)
> BugLink: http://bugs.launchpad.net/bugs/1317697
> Signed-off-by: Andy Whitcroft <apw@canonical.com>
> ---
>  arch/x86/kernel/cpu/mshyperv.c |  9 ---------
>  arch/x86/kernel/i8259.c        | 20 +++++++++++++++++++-
>  2 files changed, 19 insertions(+), 10 deletions(-)
> 
> diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c
> index 832d05a..34b520a 100644
> --- a/arch/x86/kernel/cpu/mshyperv.c
> +++ b/arch/x86/kernel/cpu/mshyperv.c
> @@ -92,15 +92,6 @@ static void __init ms_hyperv_init_platform(void)
>  		lapic_timer_frequency = hv_lapic_frequency;
>  		printk(KERN_INFO "HyperV: LAPIC Timer Frequency: %#x\n",
>  				lapic_timer_frequency);
> -
> -		/*
> -		 * On Hyper-V, when we are booting off an EFI firmware stack,
> -		 * we do not have many legacy devices including PIC, PIT etc.
> -		 */
> -		if (efi_enabled(EFI_BOOT)) {
> -			printk(KERN_INFO "HyperV: Using null_legacy_pic\n");
> -			legacy_pic = &null_legacy_pic;
> -		}
>  	}
>  #endif
>  
> diff --git a/arch/x86/kernel/i8259.c b/arch/x86/kernel/i8259.c
> index 2e977b5..8af8171 100644
> --- a/arch/x86/kernel/i8259.c
> +++ b/arch/x86/kernel/i8259.c
> @@ -299,13 +299,31 @@ static void unmask_8259A(void)
>  static void init_8259A(int auto_eoi)
>  {
>  	unsigned long flags;
> +	unsigned char probe_val = ~(1 << PIC_CASCADE_IR);
> +	unsigned char new_val;
>  
>  	i8259A_auto_eoi = auto_eoi;
>  
>  	raw_spin_lock_irqsave(&i8259A_lock, flags);
>  
> -	outb(0xff, PIC_MASTER_IMR);	/* mask all of 8259A-1 */
> +	/*
> +	 * Check to see if we have a PIC.
> +	 * Mask all except the cascade and read
> +	 * back the value we just wrote. If we don't
> +	 * have a PIC, we will read 0xff as opposed to the
> +	 * value we wrote.
> +	 */
>  	outb(0xff, PIC_SLAVE_IMR);	/* mask all of 8259A-2 */
> +	outb(probe_val, PIC_MASTER_IMR);
> +	new_val = inb(PIC_MASTER_IMR);
> +	if (new_val != probe_val) {
> +		printk(KERN_INFO "Using NULL legacy PIC\n");
> +		legacy_pic = &null_legacy_pic;
> +		raw_spin_unlock_irqrestore(&i8259A_lock, flags);
> +		return;
> +	}
> +
> +	outb(0xff, PIC_MASTER_IMR);	/* mask all of 8259A-1 */
>  
>  	/*
>  	 * outb_pic - this has to work on a wide range of PC hardware.
> 

Looks like a clean cherry-pick

Patch
diff mbox

diff --git a/arch/x86/kernel/cpu/mshyperv.c b/arch/x86/kernel/cpu/mshyperv.c
index 832d05a..34b520a 100644
--- a/arch/x86/kernel/cpu/mshyperv.c
+++ b/arch/x86/kernel/cpu/mshyperv.c
@@ -92,15 +92,6 @@  static void __init ms_hyperv_init_platform(void)
 		lapic_timer_frequency = hv_lapic_frequency;
 		printk(KERN_INFO "HyperV: LAPIC Timer Frequency: %#x\n",
 				lapic_timer_frequency);
-
-		/*
-		 * On Hyper-V, when we are booting off an EFI firmware stack,
-		 * we do not have many legacy devices including PIC, PIT etc.
-		 */
-		if (efi_enabled(EFI_BOOT)) {
-			printk(KERN_INFO "HyperV: Using null_legacy_pic\n");
-			legacy_pic = &null_legacy_pic;
-		}
 	}
 #endif
 
diff --git a/arch/x86/kernel/i8259.c b/arch/x86/kernel/i8259.c
index 2e977b5..8af8171 100644
--- a/arch/x86/kernel/i8259.c
+++ b/arch/x86/kernel/i8259.c
@@ -299,13 +299,31 @@  static void unmask_8259A(void)
 static void init_8259A(int auto_eoi)
 {
 	unsigned long flags;
+	unsigned char probe_val = ~(1 << PIC_CASCADE_IR);
+	unsigned char new_val;
 
 	i8259A_auto_eoi = auto_eoi;
 
 	raw_spin_lock_irqsave(&i8259A_lock, flags);
 
-	outb(0xff, PIC_MASTER_IMR);	/* mask all of 8259A-1 */
+	/*
+	 * Check to see if we have a PIC.
+	 * Mask all except the cascade and read
+	 * back the value we just wrote. If we don't
+	 * have a PIC, we will read 0xff as opposed to the
+	 * value we wrote.
+	 */
 	outb(0xff, PIC_SLAVE_IMR);	/* mask all of 8259A-2 */
+	outb(probe_val, PIC_MASTER_IMR);
+	new_val = inb(PIC_MASTER_IMR);
+	if (new_val != probe_val) {
+		printk(KERN_INFO "Using NULL legacy PIC\n");
+		legacy_pic = &null_legacy_pic;
+		raw_spin_unlock_irqrestore(&i8259A_lock, flags);
+		return;
+	}
+
+	outb(0xff, PIC_MASTER_IMR);	/* mask all of 8259A-1 */
 
 	/*
 	 * outb_pic - this has to work on a wide range of PC hardware.