mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
tg3: normalize inherited BCM5718 register byte order
Firmware can leave BCM5718 vendor registers byte-swapped while standard PCI fields retain normal byte order. Detect this from the host-control revision marker, byte-swap bit and swapped product ID, without matching a platform model or PCI subsystem. Prefer the normal revision marker so already-normal controllers do not enter the normalization path. Hardware swapping can accommodate big-endian register accesses, but tg3 already initializes misc_host_ctrl with WORD_SWAP set and BYTE_SWAP clear on both little- and big-endian builds. Its normal MMIO path uses readl()/writel(); on SPARC64 these use little-endian accesses. Restore that existing register mode rather than choosing a mode based on host endianness. The swab32() on the initial write compensates for the device's inherited state; subsequent accesses use the normal driver path. DMA byte ordering is controlled separately through GRC_MODE. Leave those settings, including the __BIG_ENDIAN handling for non-frame data, unchanged. Check both register readbacks and keep this in probe so PCI access or validation failures can abort initialization. Limit detection to BCM5718, whose register layout and inherited state were checked on M3000 hardware. Other controller families retain their existing initialization path. Signed-off-by: Magnus Lindholm <linmag7@gmail.com> Reviewed-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Link: https://patch.msgid.link/20261011194228.981141-1-linmag7@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
e331e66fb4
commit
4f9fbb30e3
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user