v2->v3: Fix compile warning "ahci_error_intr ISO C90 forbids mixed declarations and code"
Backport zhaoxin enhancement and bugfix patches.
LeoLiu-oc (7): rtc: Fix set RTC time delay 500ms on some Zhaoxin SOCs XHCI: Fix some device identify fail when enable xHCI runtime suspend EHCI: Clear wakeup signal locked in S0 state when device plug in Fix some bugs like plugin support and sata link stability when user enable ahci RTD3 Add support for disabling PhyRdy Change Interrupt based on actual LPM capability Add support for PxSCT.LPM set based on actual LPM capability x86/tsc: Make cur->adjusted values in package#1 to be the same
arch/x86/kernel/tsc_sync.c | 5 +++++ drivers/ata/ahci.c | 24 ++++++++++++++++++++++++ drivers/ata/libahci.c | 15 +++++++++++++++ drivers/ata/libata-eh.c | 7 +++++++ drivers/ata/libata-sata.c | 20 ++++++++++++++++++-- drivers/pci/pci-driver.c | 6 +++++- drivers/rtc/rtc-mc146818-lib.c | 16 ++++++++++++++++ drivers/usb/host/ehci-hcd.c | 21 +++++++++++++++++++++ drivers/usb/host/ehci-pci.c | 4 ++++ drivers/usb/host/ehci.h | 1 + drivers/usb/host/xhci-pci.c | 2 ++ include/linux/libata.h | 4 ++++ 12 files changed, 122 insertions(+), 3 deletions(-)
From: LeoLiu-oc LeoLiu-oc@zhaoxin.com
zhaoxin inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I40QDN CVE: NA
----------------------------------------------------------------
When the RTC divider is changed from reset to an operating time base, the first update cycle should be 500ms later. But on some Zhaoxin SOCs, this first update cycle is one second later. So set RTC time on these Zhaoxin SOCs will causing 500ms delay. Skip setup RTC divider on these SOCs in mc146818_set_time to fix it.
Signed-off-by: LeoLiu-oc LeoLiu-oc@zhaoxin.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/rtc/rtc-mc146818-lib.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
diff --git a/drivers/rtc/rtc-mc146818-lib.c b/drivers/rtc/rtc-mc146818-lib.c index 2ecd8752b088..96d9d0219394 100644 --- a/drivers/rtc/rtc-mc146818-lib.c +++ b/drivers/rtc/rtc-mc146818-lib.c @@ -171,8 +171,17 @@ int mc146818_set_time(struct rtc_time *time)
save_control = CMOS_READ(RTC_CONTROL); CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL); +#ifdef CONFIG_X86 + if (!((boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR || + boot_cpu_data.x86_vendor == X86_VENDOR_ZHAOXIN) && + (boot_cpu_data.x86 <= 7 && boot_cpu_data.x86_model <= 59))) { + save_freq_select = CMOS_READ(RTC_FREQ_SELECT); + CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); + } +#else save_freq_select = CMOS_READ(RTC_FREQ_SELECT); CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT); +#endif
#ifdef CONFIG_MACH_DECSTATION CMOS_WRITE(real_yrs, RTC_DEC_YEAR); @@ -190,7 +199,14 @@ int mc146818_set_time(struct rtc_time *time) #endif
CMOS_WRITE(save_control, RTC_CONTROL); +#ifdef CONFIG_X86 + if (!((boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR || + boot_cpu_data.x86_vendor == X86_VENDOR_ZHAOXIN) && + (boot_cpu_data.x86 <= 7 && boot_cpu_data.x86_model <= 59))) + CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); +#else CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); +#endif
spin_unlock_irqrestore(&rtc_lock, flags);
From: LeoLiu-oc LeoLiu-oc@zhaoxin.com
zhaoxin inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I40QDN CVE: NA
----------------------------------------------------------------
If plug out device form xhci with runtime suspend enabled. On the one hand, driver will disconnect this device and send disabled slot command to xhci. On the other hand, without no device connect to xhci, PM core will call xhci suspend function to let xhci go to D3 to save power. However there is a temporal competition to get xhci lock between disable slot command interrupt and xhci suspend. If xhci suspend function get xhci lock first, then this function will clear xhci command ring. It will get error command trb when driver to handle disable slot command interrupt. This is a serious error for driver and driver will cleanup xhci. So,any device connect to this xhci port again will not be recognized.
In order to fix this issues, we let disable slot command interrupt ISR to get xhci lock first. So, add a delay in xhci suspend function before to get xhci lock.
Signed-off-by: LeoLiu-oc LeoLiu-oc@zhaoxin.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/usb/host/xhci-pci.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 188dcfa2c7ee..caae5c54502a 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -286,6 +286,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) xhci->quirks |= XHCI_LPM_SUPPORT; xhci->quirks |= XHCI_ZHAOXIN_HOST; } + if (pdev->vendor == PCI_VENDOR_ID_ZHAOXIN) + xhci->quirks |= XHCI_SUSPEND_DELAY;
/* See https://bugzilla.kernel.org/show_bug.cgi?id=79511 */ if (pdev->vendor == PCI_VENDOR_ID_VIA &&
From: LeoLiu-oc LeoLiu-oc@zhaoxin.com
zhaoxin inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I40QDN CVE: NA
----------------------------------------------------------------
If we plug in a LS/FS device on USB2 port of EHCI, it will latch a wakeup signal in EHCI internal. This is a bug of EHCI for Some project of ZhaoXin. If enable EHCI runtime suspend and no device attach. PM core will let EHCI go to D3 to save power. However, once EHCI go to D3, it will release wakeup signal that latched on device connect to port during S0. Which will generate a SCI interrupt and bring EHCI to D0. But without device connect, EHCI will go to D3 again. So, there is suspend-resume loop and generate SCI interrupt Continuously.
In order to fix this issues, we need to clear the wakeup signal latched in EHCI when EHCI suspend function is called.
Signed-off-by: LeoLiu-oc LeoLiu-oc@zhaoxin.com Signed-off-by: Zheng Zengkai zhengzengkai@huawei.com --- drivers/pci/pci-driver.c | 6 +++++- drivers/usb/host/ehci-hcd.c | 21 +++++++++++++++++++++ drivers/usb/host/ehci-pci.c | 4 ++++ drivers/usb/host/ehci.h | 1 + 4 files changed, 31 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 8b587fc97f7b..c33d7e0a60b5 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -518,7 +518,11 @@ static int pci_restore_standard_config(struct pci_dev *pci_dev) }
pci_restore_state(pci_dev); - pci_pme_restore(pci_dev); + if (!((pci_dev->vendor == PCI_VENDOR_ID_ZHAOXIN) && + (pci_dev->device == 0x3104) && + ((pci_dev->revision & 0xf0) == 0x90)) || + !(pci_dev->class == PCI_CLASS_SERIAL_USB_EHCI)) + pci_pme_restore(pci_dev); return 0; }
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 8aff19ff8e8f..586e2735d6e0 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1142,6 +1142,27 @@ int ehci_suspend(struct usb_hcd *hcd, bool do_wakeup) return -EBUSY; }
+ /*clear wakeup signal locked in S0 state when device plug in*/ + if (ehci->zx_wakeup_clear == 1) { + u32 __iomem *reg = &ehci->regs->port_status[4]; + u32 t1 = ehci_readl(ehci, reg); + + t1 &= (u32)~0xf0000; + t1 |= PORT_TEST_FORCE; + ehci_writel(ehci, t1, reg); + t1 = ehci_readl(ehci, reg); + usleep_range(1000, 2000); + t1 &= (u32)~0xf0000; + ehci_writel(ehci, t1, reg); + usleep_range(1000, 2000); + t1 = ehci_readl(ehci, reg); + ehci_writel(ehci, t1 | PORT_CSC, reg); + udelay(500); + t1 = ehci_readl(ehci, &ehci->regs->status); + ehci_writel(ehci, t1 & STS_PCD, &ehci->regs->status); + ehci_readl(ehci, &ehci->regs->status); + } + return 0; } EXPORT_SYMBOL_GPL(ehci_suspend); diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index e87cf3a00fa4..a5e27deda83a 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -222,6 +222,10 @@ static int ehci_pci_setup(struct usb_hcd *hcd) ehci->has_synopsys_hc_bug = 1; } break; + case PCI_VENDOR_ID_ZHAOXIN: + if (pdev->device == 0x3104 && (pdev->revision & 0xf0) == 0x90) + ehci->zx_wakeup_clear = 1; + break; }
/* optional debug port, normally in the first BAR */ diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 59fd523c55f3..8da080a54668 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -219,6 +219,7 @@ struct ehci_hcd { /* one per controller */ unsigned need_oc_pp_cycle:1; /* MPC834X port power */ unsigned imx28_write_fix:1; /* For Freescale i.MX28 */ unsigned is_aspeed:1; + unsigned zx_wakeup_clear:1;
/* required for usb32 quirk */ #define OHCI_CTRL_HCFS (3 << 6)
From: LeoLiu-oc LeoLiu-oc@zhaoxin.com
zhaoxin inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I40QDN CVE: NA
----------------------------------------------------------------
The kernel driver now will disable interrupt when port is suspended, causing plugin not work. It is useful to make plugin work,when the plugin interrupt is enabled with power management status. Adding pm_request_resume() is to reume port for plugin or PME signal waking up controller which in D3.
with the AHCI controller frequently enters into D3 and leaves from D3, the identify cmd may be timeout when controller resumes and establishes a connect with the device.it is effective to delay 10ms between controller resume and port resume,with link’s smooth transition.
with non power management request and power management competing with each other in queue, it is often found that block IO hang 120s when system disk is suspending or resuming.it is now guaranteed that PM requests will enter the queue no matter other non-PM requests are waiting. Increase the pm_only counter before checking whether any non-PM blk_queue_enter() calls are in progress. Meanwhile, the new blk_pm_request_resume() call is necessary to occur during request assigned to a queue when device is suspended.
Signed-off-by: LeoLiu-oc LeoLiu-oc@zhaoxin.com --- drivers/ata/ahci.c | 13 +++++++++++++ drivers/ata/libahci.c | 15 +++++++++++++++ 2 files changed, 28 insertions(+)
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index ff2add0101fe..8a7140ee88b5 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -869,6 +869,19 @@ static int ahci_pci_device_runtime_resume(struct device *dev) if (rc) return rc; ahci_pci_init_controller(host); + + /* Port resume for Zhaoxin platform */ + if (pdev->vendor == PCI_VENDOR_ID_ZHAOXIN) { + if (pdev->revision == 0x01) + ata_msleep(NULL, 10); + + for (rc = 0; rc < host->n_ports; rc++) { + struct ata_port *ap = host->ports[rc]; + + pm_request_resume(&ap->tdev); + } + } + return 0; }
diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c index fec2e9754aed..4514f3f28b7c 100644 --- a/drivers/ata/libahci.c +++ b/drivers/ata/libahci.c @@ -823,9 +823,15 @@ static int ahci_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, static void ahci_power_down(struct ata_port *ap) { struct ahci_host_priv *hpriv = ap->host->private_data; + struct pci_dev *pdev; void __iomem *port_mmio = ahci_port_base(ap); u32 cmd, scontrol;
+ /* port suspended enable Plugin intr for Zhaoxin platform */ + pdev = (ap->dev && dev_is_pci(ap->dev)) ? to_pci_dev(ap->dev) : NULL; + if ((pdev && pdev->vendor == PCI_VENDOR_ID_ZHAOXIN) && !ap->link.device->sdev) + writel(PORT_IRQ_CONNECT, port_mmio + PORT_IRQ_MASK); + if (!(hpriv->cap & HOST_CAP_SSS)) return;
@@ -1701,6 +1707,7 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) struct ata_link *link = NULL; struct ata_queued_cmd *active_qc; struct ata_eh_info *active_ehi; + struct pci_dev *pdev; bool fbs_need_dec = false; u32 serror;
@@ -1791,6 +1798,14 @@ static void ahci_error_intr(struct ata_port *ap, u32 irq_stat) ata_ehi_push_desc(host_ehi, "%s", irq_stat & PORT_IRQ_CONNECT ? "connection status changed" : "PHY RDY changed"); + + /* When plugin intr happen, now resume suspended port for Zhaoxin platform */ + pdev = (ap->dev && dev_is_pci(ap->dev)) ? to_pci_dev(ap->dev) : NULL; + if ((pdev && pdev->vendor == PCI_VENDOR_ID_ZHAOXIN) && + (ap->pflags & ATA_PFLAG_SUSPENDED)) { + pm_request_resume(&ap->tdev); + return; + } }
/* okay, let's hand over to EH */
From: LeoLiu-oc LeoLiu-oc@zhaoxin.com
zhaoxin inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I40QDN CVE: NA
----------------------------------------------------------------
The ahci spec mentions that PhyRdy Change Interrupt and Link Power Management (LPM) do not coexist. However, before enabling LPM, the driver did not check whether the host supports LPM, but directly disabled PhyRdy Change Interrupt. Increase the judgment on the actual support of LPM, and disable PhyRdy Change Interrupt only when it is supported.
Signed-off-by: LeoLiu-oc LeoLiu-oc@zhaoxin.com --- drivers/ata/ahci.c | 11 +++++++++++ drivers/ata/libata-eh.c | 7 +++++++ include/linux/libata.h | 4 ++++ 3 files changed, 22 insertions(+)
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index 8a7140ee88b5..abc2df4a96be 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -1881,6 +1881,17 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) else dev_info(&pdev->dev, "SSS flag set, parallel bus scan disabled\n");
+ if (pdev->vendor == PCI_VENDOR_ID_ZHAOXIN) { + if (hpriv->cap & HOST_CAP_PART) + host->flags |= ATA_HOST_PART; + + if (hpriv->cap & HOST_CAP_SSC) + host->flags |= ATA_HOST_SSC; + + if (hpriv->cap2 & HOST_CAP2_SDS) + host->flags |= ATA_HOST_DEVSLP; + } + if (pi.flags & ATA_FLAG_EM) ahci_reset_em(host);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c index 018ed8736a64..271c3c76f4af 100644 --- a/drivers/ata/libata-eh.c +++ b/drivers/ata/libata-eh.c @@ -3237,6 +3237,8 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, struct ata_device **r_failed_dev) { struct ata_port *ap = ata_is_host_link(link) ? link->ap : NULL; + struct device *device = ap->host->dev; + struct pci_dev *pdev = (!device || !dev_is_pci(device)) ? NULL : to_pci_dev(device); struct ata_eh_context *ehc = &link->eh_context; struct ata_device *dev, *link_dev = NULL, *lpm_dev = NULL; enum ata_lpm_policy old_policy = link->lpm_policy; @@ -3245,6 +3247,11 @@ static int ata_eh_set_lpm(struct ata_link *link, enum ata_lpm_policy policy, unsigned int err_mask; int rc;
+ /* if controller does not support lpm, then sets no LPM flags*/ + if ((pdev && pdev->vendor == PCI_VENDOR_ID_ZHAOXIN) && + !(ap->host->flags & (ATA_HOST_PART | ATA_HOST_SSC | ATA_HOST_DEVSLP))) + link->flags |= ATA_LFLAG_NO_LPM; + /* if the link or host doesn't do LPM, noop */ if (!IS_ENABLED(CONFIG_SATA_HOST) || (link->flags & ATA_LFLAG_NO_LPM) || (ap && !ap->ops->set_lpm)) diff --git a/include/linux/libata.h b/include/linux/libata.h index d3600fc7f7c4..bbce7a124286 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h @@ -260,6 +260,10 @@ enum { ATA_HOST_PARALLEL_SCAN = (1 << 2), /* Ports on this host can be scanned in parallel */ ATA_HOST_IGNORE_ATA = (1 << 3), /* Ignore ATA devices on this host. */
+ ATA_HOST_PART = (1 << 4), /* Host support partial.*/ + ATA_HOST_SSC = (1 << 5), /* Host support slumber.*/ + ATA_HOST_DEVSLP = (1 << 6), /* Host support devslp.*/ + /* bits 24:31 of host->flags are reserved for LLD specific flags */
/* various lengths of time */
From: LeoLiu-oc LeoLiu-oc@zhaoxin.com
zhaoxin inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I40QDN CVE: NA
----------------------------------------------------------------
The ahci spec mentions that when PxCMD.PSC/SSC is cleared to '0', the PxSCTL.LPM field in each port must be programmed to disallow device initiated Partial/Slumber requests.
Signed-off-by: LeoLiu-oc LeoLiu-oc@zhaoxin.com --- drivers/ata/libata-sata.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/drivers/ata/libata-sata.c b/drivers/ata/libata-sata.c index c16423e44525..5a722c64b7dd 100644 --- a/drivers/ata/libata-sata.c +++ b/drivers/ata/libata-sata.c @@ -8,6 +8,7 @@ */
#include <linux/kernel.h> +#include <linux/pci.h> #include <linux/module.h> #include <scsi/scsi_cmnd.h> #include <scsi/scsi_device.h> @@ -368,6 +369,10 @@ int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy, bool spm_wakeup) { struct ata_eh_context *ehc = &link->eh_context; + struct ata_port *ap = ata_is_host_link(link) ? link->ap : NULL; + struct device *dev = ap ? ap->host->dev : NULL; + struct pci_dev *pdev = (!dev || !dev_is_pci(dev)) ? NULL : to_pci_dev(dev); + bool woken_up = false; u32 scontrol; int rc; @@ -394,10 +399,21 @@ int sata_link_scr_lpm(struct ata_link *link, enum ata_lpm_policy policy, case ATA_LPM_MED_POWER_WITH_DIPM: case ATA_LPM_MIN_POWER_WITH_PARTIAL: case ATA_LPM_MIN_POWER: - if (ata_link_nr_enabled(link) > 0) + if (ata_link_nr_enabled(link) > 0) { /* no restrictions on LPM transitions */ scontrol &= ~(0x7 << 8); - else { + + /* if controller does not support partial, then disallows it, + * the same for slumber + */ + if (pdev && pdev->vendor == PCI_VENDOR_ID_ZHAOXIN) { + if (!(link->ap->host->flags & ATA_HOST_PART)) + scontrol |= (0x1 << 8); + + if (!(link->ap->host->flags & ATA_HOST_SSC)) + scontrol |= (0x2 << 8); + } + } else { /* empty port, power off */ scontrol &= ~0xf; scontrol |= (0x1 << 2);
From: LeoLiu-oc LeoLiu-oc@zhaoxin.com
zhaoxin inclusion category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/I40QDN CVE: NA
----------------------------------------------------------------
When resume from S4 on Zhaoxin 2 packages platform that support X86_FEATURE_TSC_ADJUST, the following warning messages appear:
[ 327.445302] [Firmware Bug]: TSC ADJUST differs: CPU15 45960750 --> 78394770. Restoring [ 329.209120] [Firmware Bug]: TSC ADJUST differs: CPU14 45960750 --> 78394770. Restoring [ 329.209128] [Firmware Bug]: TSC ADJUST differs: CPU13 45960750 --> 78394770. Restoring [ 329.209138] [Firmware Bug]: TSC ADJUST differs: CPU12 45960750 --> 78394770. Restoring [ 329.209151] [Firmware Bug]: TSC ADJUST differs: CPU11 45960750 --> 78394770. Restoring [ 329.209160] [Firmware Bug]: TSC ADJUST differs: CPU10 45960750 --> 78394770. Restoring [ 329.209169] [Firmware Bug]: TSC ADJUST differs: CPU9 45960750 --> 78394770. Restoring
The reason is:
Step 1: Bring up. TSC is sync after bring up with following settings: MSR 0x3b cur->adjusted Package#0 CPU 0-7 0 0 Package#1 first CPU value1 value1 Package#1 non-first CPU value1 value1
Step 2: Suspend to S4. Settings in Step 1 are not changed in this Step.
Step 3: Bring up caused by S4 wake up event. TSC is sync when bring up with following settings: MSR 0x3b cur->adjusted Package#0 CPU 0-7 0 0 Package#1 first CPU value2 value2 Package#1 non-first CPU value2 value2
Step 4: Resume from S4. When resuming from S4, Current TSC synchronous mechanism cause following settings: MSR 0x3b cur->adjusted Package#0 CPU 0-7 0 0 Package#1 first CPU value2 value2 Package#1 non-first CPU value2 value1
In these Steps, value1 != 0 and value2 != value1.
In Step4, as function tsc_store_and_check_tsc_adjust() do, when the value of MSR 0x3b on the non-first online CPU in package#1 is equal to the value of cur->adjusted on the first online CPU in the same package, the cur->adjusted value on this non-first online CPU will hold the old value1. This cause function tsc_verify_tsc_adjust() set the value of MSR 0x3b on the non-first online CPUs in the package#1 to the old value1 and print the beginning warning messages.
Fix it by setting cur->adjusted value on the non-first online CPU in a package to the value of MSR 0x3b on the same CPU when they are not equal.
Signed-off-by: LeoLiu-oc LeoLiu-oc@zhaoxin.com --- arch/x86/kernel/tsc_sync.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/arch/x86/kernel/tsc_sync.c b/arch/x86/kernel/tsc_sync.c index 923660057f36..bb59e6af2cde 100644 --- a/arch/x86/kernel/tsc_sync.c +++ b/arch/x86/kernel/tsc_sync.c @@ -231,6 +231,11 @@ bool tsc_store_and_check_tsc_adjust(bool bootcpu) if (bootval != ref->adjusted) { cur->adjusted = ref->adjusted; wrmsrl(MSR_IA32_TSC_ADJUST, ref->adjusted); + } else if (cur->adjusted != bootval) { + if (boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR || + boot_cpu_data.x86_vendor == X86_VENDOR_ZHAOXIN) { + cur->adjusted = bootval; + } } /* * We have the TSCs forced to be in sync on this package. Skip sync