Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 654ede20 authored by Jason Uhlenkott's avatar Jason Uhlenkott Committed by Linus Torvalds
Browse files

drivers/edac: mod race fix i82875p



If ERRSTS indicates that there's no error then we don't need to bother reading
the other registers.

In addition to making the common case faster, this actually fixes a small race
where we don't see an error but we clear the error bits anyway, potentially
wiping away info on an error that happened in the interim (or where a CE
arrives between the first and second read of ERRSTS, causing us to falsely
claim "UE overwrote CE").

Signed-off-by: default avatarJason Uhlenkott <juhlenko@akamai.com>
Signed-off-by: default avatarDouglas Thompson <dougthompson@xmission.com>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent b113a3f7
Loading
Loading
Loading
Loading
+7 −6
Original line number Original line Diff line number Diff line
@@ -198,27 +198,28 @@ static void i82875p_get_error_info(struct mem_ctl_info *mci,
	 * overwritten by UE.
	 * overwritten by UE.
	 */
	 */
	pci_read_config_word(pdev, I82875P_ERRSTS, &info->errsts);
	pci_read_config_word(pdev, I82875P_ERRSTS, &info->errsts);

	if (!(info->errsts & 0x0081))
		return;

	pci_read_config_dword(pdev, I82875P_EAP, &info->eap);
	pci_read_config_dword(pdev, I82875P_EAP, &info->eap);
	pci_read_config_byte(pdev, I82875P_DES, &info->des);
	pci_read_config_byte(pdev, I82875P_DES, &info->des);
	pci_read_config_byte(pdev, I82875P_DERRSYN, &info->derrsyn);
	pci_read_config_byte(pdev, I82875P_DERRSYN, &info->derrsyn);
	pci_read_config_word(pdev, I82875P_ERRSTS, &info->errsts2);
	pci_read_config_word(pdev, I82875P_ERRSTS, &info->errsts2);


	pci_write_bits16(pdev, I82875P_ERRSTS, 0x0081, 0x0081);

	/*
	/*
	 * If the error is the same then we can for both reads then
	 * If the error is the same then we can for both reads then
	 * the first set of reads is valid.  If there is a change then
	 * the first set of reads is valid.  If there is a change then
	 * there is a CE no info and the second set of reads is valid
	 * there is a CE no info and the second set of reads is valid
	 * and should be UE info.
	 * and should be UE info.
	 */
	 */
	if (!(info->errsts2 & 0x0081))
		return;

	if ((info->errsts ^ info->errsts2) & 0x0081) {
	if ((info->errsts ^ info->errsts2) & 0x0081) {
		pci_read_config_dword(pdev, I82875P_EAP, &info->eap);
		pci_read_config_dword(pdev, I82875P_EAP, &info->eap);
		pci_read_config_byte(pdev, I82875P_DES, &info->des);
		pci_read_config_byte(pdev, I82875P_DES, &info->des);
		pci_read_config_byte(pdev, I82875P_DERRSYN, &info->derrsyn);
		pci_read_config_byte(pdev, I82875P_DERRSYN, &info->derrsyn);
	}
	}

	pci_write_bits16(pdev, I82875P_ERRSTS, 0x0081, 0x0081);
}
}


static int i82875p_process_error_info(struct mem_ctl_info *mci,
static int i82875p_process_error_info(struct mem_ctl_info *mci,
@@ -229,7 +230,7 @@ static int i82875p_process_error_info(struct mem_ctl_info *mci,


	multi_chan = mci->csrows[0].nr_channels - 1;
	multi_chan = mci->csrows[0].nr_channels - 1;


	if (!(info->errsts2 & 0x0081))
	if (!(info->errsts & 0x0081))
		return 0;
		return 0;


	if (!handle_errors)
	if (!handle_errors)