diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 8b6806a79edf..cc618f8beb3f 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -16248,6 +16248,65 @@ static bool tg3_10_100_only_device(struct tg3 *tp, return false; } +static int tg3_fw_byteorder(struct tg3 *tp, u32 *misc_ctrl_reg) +{ + struct pci_dev *pdev = tp->pdev; + u32 prodid, expected_prodid, normalized, readback; + int reg, err; + + /* Prefer the normal revision marker before testing the swapped state. */ + if (pdev->device != TG3PCI_DEVICE_TIGON3_5718 || + (*misc_ctrl_reg >> 28) == ASIC_REV_USE_PROD_ID_REG || + (swab32(*misc_ctrl_reg) >> 28) != ASIC_REV_USE_PROD_ID_REG || + !(swab32(*misc_ctrl_reg) & MISC_HOST_CTRL_BYTE_SWAP)) + return 0; + + /* Standard PCI fields are normal; verify the swapped vendor registers. */ + reg = TG3PCI_GEN2_PRODID_ASICREV; + err = pci_read_config_dword(pdev, reg, &prodid); + if (err) + goto config_error; + expected_prodid = swab32(prodid); + if ((expected_prodid >> 12) != ASIC_REV_5717) { + dev_err(&pdev->dev, "unexpected swapped BCM5718 product ID %08x\n", + prodid); + return -ENODEV; + } + + normalized = (swab32(*misc_ctrl_reg) & MISC_HOST_CTRL_CHIPREV) | + tp->misc_host_ctrl; + reg = TG3PCI_MISC_HOST_CTRL; + err = pci_write_config_dword(pdev, reg, swab32(normalized)); + if (err) + goto config_error; + err = pci_read_config_dword(pdev, reg, &readback); + if (err) + goto config_error; + if (readback != normalized) { + dev_err(&pdev->dev, "BCM5718 host-control readback mismatch %08x\n", + readback); + return -EIO; + } + + reg = TG3PCI_GEN2_PRODID_ASICREV; + err = pci_read_config_dword(pdev, reg, &prodid); + if (err) + goto config_error; + if (prodid != expected_prodid) { + dev_err(&pdev->dev, "BCM5718 product-ID readback mismatch %08x\n", + prodid); + return -EIO; + } + *misc_ctrl_reg = readback; + dev_dbg(&pdev->dev, "normalized firmware register byte order\n"); + return 0; + +config_error: + dev_err(&pdev->dev, "BCM5718 PCI config access at %#x failed (%d)\n", + reg, err); + return pcibios_err_to_errno(err); +} + static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent) { u32 misc_ctrl_reg; @@ -16272,8 +16331,17 @@ static int tg3_get_invariants(struct tg3 *tp, const struct pci_device_id *ent) * sure that indirect register accesses are enabled before * the first operation. */ - pci_read_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL, - &misc_ctrl_reg); + err = pci_read_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL, + &misc_ctrl_reg); + if (err && tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718) { + dev_err(&tp->pdev->dev, "PCI host-control read failed (%d)\n", + err); + return pcibios_err_to_errno(err); + } + err = tg3_fw_byteorder(tp, &misc_ctrl_reg); + if (err) + return err; + tp->misc_host_ctrl |= (misc_ctrl_reg & MISC_HOST_CTRL_CHIPREV); pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL,