x86/apic: Implement EIO micro-optimization
[firefly-linux-kernel-4.4.55.git] / arch / x86 / include / asm / apic.h
index d854101712608655a67e10a46ff7b964245798c7..eaff4790ed96c207d2ac51e0c89901707b5285ec 100644 (file)
@@ -138,6 +138,11 @@ static inline void native_apic_msr_write(u32 reg, u32 v)
        wrmsr(APIC_BASE_MSR + (reg >> 4), v, 0);
 }
 
+static inline void native_apic_msr_eoi_write(u32 reg, u32 v)
+{
+       wrmsr(APIC_BASE_MSR + (APIC_EOI >> 4), APIC_EOI_ACK, 0);
+}
+
 static inline u32 native_apic_msr_read(u32 reg)
 {
        u64 msr;
@@ -351,6 +356,14 @@ struct apic {
        /* apic ops */
        u32 (*read)(u32 reg);
        void (*write)(u32 reg, u32 v);
+       /*
+        * ->eoi_write() has the same signature as ->write().
+        *
+        * Drivers can support both ->eoi_write() and ->write() by passing the same
+        * callback value. Kernel can override ->eoi_write() and fall back
+        * on write for EOI.
+        */
+       void (*eoi_write)(u32 reg, u32 v);
        u64 (*icr_read)(void);
        void (*icr_write)(u32 low, u32 high);
        void (*wait_icr_idle)(void);
@@ -426,6 +439,11 @@ static inline void apic_write(u32 reg, u32 val)
        apic->write(reg, val);
 }
 
+static inline void apic_eoi(void)
+{
+       apic->eoi_write(APIC_EOI, APIC_EOI_ACK);
+}
+
 static inline u64 apic_icr_read(void)
 {
        return apic->icr_read();
@@ -450,6 +468,7 @@ static inline u32 safe_apic_wait_icr_idle(void)
 
 static inline u32 apic_read(u32 reg) { return 0; }
 static inline void apic_write(u32 reg, u32 val) { }
+static inline void apic_eoi(void) { }
 static inline u64 apic_icr_read(void) { return 0; }
 static inline void apic_icr_write(u32 low, u32 high) { }
 static inline void apic_wait_icr_idle(void) { }
@@ -463,9 +482,7 @@ static inline void ack_APIC_irq(void)
         * ack_APIC_irq() actually gets compiled as a single instruction
         * ... yummie.
         */
-
-       /* Docs say use 0 for future compatibility */
-       apic_write(APIC_EOI, 0);
+       apic_eoi();
 }
 
 static inline unsigned default_get_apic_id(unsigned long x)