Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 6293
b: refs/heads/master
c: 6892914
h: refs/heads/master
i:
  6291: 70e03c4
v: v3
  • Loading branch information
Michael Chan authored and David S. Miller committed Aug 29, 2005
1 parent 6fed375 commit 3c8dae4
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 29 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 09ee929cccfd0b56ea3724b3c6299fbbe813df43
refs/heads/master: 6892914fb7980d844f2bac859f4095df9ebd18da
190 changes: 162 additions & 28 deletions trunk/drivers/net/tg3.c
Original file line number Diff line number Diff line change
Expand Up @@ -340,10 +340,12 @@ static struct {

static void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val)
{
spin_lock_bh(&tp->indirect_lock);
unsigned long flags;

spin_lock_irqsave(&tp->indirect_lock, flags);
pci_write_config_dword(tp->pdev, TG3PCI_REG_BASE_ADDR, off);
pci_write_config_dword(tp->pdev, TG3PCI_REG_DATA, val);
spin_unlock_bh(&tp->indirect_lock);
spin_unlock_irqrestore(&tp->indirect_lock, flags);
}

static void tg3_write_flush_reg32(struct tg3 *tp, u32 off, u32 val)
Expand All @@ -352,24 +354,75 @@ static void tg3_write_flush_reg32(struct tg3 *tp, u32 off, u32 val)
readl(tp->regs + off);
}

static void _tw32_flush(struct tg3 *tp, u32 off, u32 val)
static u32 tg3_read_indirect_reg32(struct tg3 *tp, u32 off)
{
if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) != 0) {
spin_lock_bh(&tp->indirect_lock);
pci_write_config_dword(tp->pdev, TG3PCI_REG_BASE_ADDR, off);
pci_write_config_dword(tp->pdev, TG3PCI_REG_DATA, val);
spin_unlock_bh(&tp->indirect_lock);
} else {
void __iomem *dest = tp->regs + off;
writel(val, dest);
readl(dest); /* always flush PCI write */
unsigned long flags;
u32 val;

spin_lock_irqsave(&tp->indirect_lock, flags);
pci_write_config_dword(tp->pdev, TG3PCI_REG_BASE_ADDR, off);
pci_read_config_dword(tp->pdev, TG3PCI_REG_DATA, &val);
spin_unlock_irqrestore(&tp->indirect_lock, flags);
return val;
}

static void tg3_write_indirect_mbox(struct tg3 *tp, u32 off, u32 val)
{
unsigned long flags;

if (off == (MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW)) {
pci_write_config_dword(tp->pdev, TG3PCI_RCV_RET_RING_CON_IDX +
TG3_64BIT_REG_LOW, val);
return;
}
if (off == (MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW)) {
pci_write_config_dword(tp->pdev, TG3PCI_STD_RING_PROD_IDX +
TG3_64BIT_REG_LOW, val);
return;
}

spin_lock_irqsave(&tp->indirect_lock, flags);
pci_write_config_dword(tp->pdev, TG3PCI_REG_BASE_ADDR, off + 0x5600);
pci_write_config_dword(tp->pdev, TG3PCI_REG_DATA, val);
spin_unlock_irqrestore(&tp->indirect_lock, flags);

/* In indirect mode when disabling interrupts, we also need
* to clear the interrupt bit in the GRC local ctrl register.
*/
if ((off == (MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW)) &&
(val == 0x1)) {
pci_write_config_dword(tp->pdev, TG3PCI_MISC_LOCAL_CTRL,
tp->grc_local_ctrl|GRC_LCLCTRL_CLEARINT);
}
}

static u32 tg3_read_indirect_mbox(struct tg3 *tp, u32 off)
{
unsigned long flags;
u32 val;

spin_lock_irqsave(&tp->indirect_lock, flags);
pci_write_config_dword(tp->pdev, TG3PCI_REG_BASE_ADDR, off + 0x5600);
pci_read_config_dword(tp->pdev, TG3PCI_REG_DATA, &val);
spin_unlock_irqrestore(&tp->indirect_lock, flags);
return val;
}

static void _tw32_flush(struct tg3 *tp, u32 off, u32 val)
{
tp->write32(tp, off, val);
if (!(tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) &&
!(tp->tg3_flags & TG3_FLAG_5701_REG_WRITE_BUG) &&
!(tp->tg3_flags2 & TG3_FLG2_ICH_WORKAROUND))
tp->read32(tp, off); /* flush */
}

static inline void tw32_mailbox_flush(struct tg3 *tp, u32 off, u32 val)
{
tp->write32_mbox(tp, off, val);
tp->read32_mbox(tp, off);
if (!(tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) &&
!(tp->tg3_flags2 & TG3_FLG2_ICH_WORKAROUND))
tp->read32_mbox(tp, off);
}

static void tg3_write32_tx_mbox(struct tg3 *tp, u32 off, u32 val)
Expand Down Expand Up @@ -404,24 +457,28 @@ static u32 tg3_read32(struct tg3 *tp, u32 off)

static void tg3_write_mem(struct tg3 *tp, u32 off, u32 val)
{
spin_lock_bh(&tp->indirect_lock);
unsigned long flags;

spin_lock_irqsave(&tp->indirect_lock, flags);
pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);

/* Always leave this as zero. */
pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
spin_unlock_bh(&tp->indirect_lock);
spin_unlock_irqrestore(&tp->indirect_lock, flags);
}

static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val)
{
spin_lock_bh(&tp->indirect_lock);
unsigned long flags;

spin_lock_irqsave(&tp->indirect_lock, flags);
pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
pci_read_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);

/* Always leave this as zero. */
pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
spin_unlock_bh(&tp->indirect_lock);
spin_unlock_irqrestore(&tp->indirect_lock, flags);
}

static void tg3_disable_ints(struct tg3 *tp)
Expand Down Expand Up @@ -9149,14 +9206,6 @@ static int __devinit tg3_is_sun_570X(struct tg3 *tp)
static int __devinit tg3_get_invariants(struct tg3 *tp)
{
static struct pci_device_id write_reorder_chipsets[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82801AA_8) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82801AB_8) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82801BA_11) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82801BA_6) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD,
PCI_DEVICE_ID_AMD_FE_GATE_700C) },
{ },
Expand All @@ -9173,7 +9222,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
tp->tg3_flags2 |= TG3_FLG2_SUN_570X;
#endif

/* If we have an AMD 762 or Intel ICH/ICH0/ICH2 chipset, write
/* If we have an AMD 762 chipset, write
* reordering to the mailbox registers done by the host
* controller can cause major troubles. We read back from
* every mailbox register write to force the writes to be
Expand Down Expand Up @@ -9211,6 +9260,69 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
if (tp->pci_chip_rev_id == CHIPREV_ID_5752_A0_HW)
tp->pci_chip_rev_id = CHIPREV_ID_5752_A0;

/* If we have 5702/03 A1 or A2 on certain ICH chipsets,
* we need to disable memory and use config. cycles
* only to access all registers. The 5702/03 chips
* can mistakenly decode the special cycles from the
* ICH chipsets as memory write cycles, causing corruption
* of register and memory space. Only certain ICH bridges
* will drive special cycles with non-zero data during the
* address phase which can fall within the 5703's address
* range. This is not an ICH bug as the PCI spec allows
* non-zero address during special cycles. However, only
* these ICH bridges are known to drive non-zero addresses
* during special cycles.
*
* Since special cycles do not cross PCI bridges, we only
* enable this workaround if the 5703 is on the secondary
* bus of these ICH bridges.
*/
if ((tp->pci_chip_rev_id == CHIPREV_ID_5703_A1) ||
(tp->pci_chip_rev_id == CHIPREV_ID_5703_A2)) {
static struct tg3_dev_id {
u32 vendor;
u32 device;
u32 rev;
} ich_chipsets[] = {
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_8,
PCI_ANY_ID },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_8,
PCI_ANY_ID },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_11,
0xa },
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_6,
PCI_ANY_ID },
{ },
};
struct tg3_dev_id *pci_id = &ich_chipsets[0];
struct pci_dev *bridge = NULL;

while (pci_id->vendor != 0) {
bridge = pci_get_device(pci_id->vendor, pci_id->device,
bridge);
if (!bridge) {
pci_id++;
continue;
}
if (pci_id->rev != PCI_ANY_ID) {
u8 rev;

pci_read_config_byte(bridge, PCI_REVISION_ID,
&rev);
if (rev > pci_id->rev)
continue;
}
if (bridge->subordinate &&
(bridge->subordinate->number ==
tp->pdev->bus->number)) {

tp->tg3_flags2 |= TG3_FLG2_ICH_WORKAROUND;
pci_dev_put(bridge);
break;
}
}
}

/* Find msi capability. */
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5780)
tp->msi_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_MSI);
Expand Down Expand Up @@ -9342,6 +9454,22 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
tp->write32_rx_mbox = tg3_write_flush_reg32;
}

if (tp->tg3_flags2 & TG3_FLG2_ICH_WORKAROUND) {
tp->read32 = tg3_read_indirect_reg32;
tp->write32 = tg3_write_indirect_reg32;
tp->read32_mbox = tg3_read_indirect_mbox;
tp->write32_mbox = tg3_write_indirect_mbox;
tp->write32_tx_mbox = tg3_write_indirect_mbox;
tp->write32_rx_mbox = tg3_write_indirect_mbox;

iounmap(tp->regs);
tp->regs = 0;

pci_read_config_word(tp->pdev, PCI_COMMAND, &pci_cmd);
pci_cmd &= ~PCI_COMMAND_MEMORY;
pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd);
}

/* Get eeprom hw config before calling tg3_set_power_state().
* In particular, the TG3_FLAG_EEPROM_WRITE_PROT flag must be
* determined before calling tg3_set_power_state() so that
Expand Down Expand Up @@ -10486,7 +10614,10 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
return 0;

err_out_iounmap:
iounmap(tp->regs);
if (tp->regs) {
iounmap(tp->regs);
tp->regs = 0;
}

err_out_free_dev:
free_netdev(dev);
Expand All @@ -10508,7 +10639,10 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev)
struct tg3 *tp = netdev_priv(dev);

unregister_netdev(dev);
iounmap(tp->regs);
if (tp->regs) {
iounmap(tp->regs);
tp->regs = 0;
}
free_netdev(dev);
pci_release_regions(pdev);
pci_disable_device(pdev);
Expand Down
1 change: 1 addition & 0 deletions trunk/drivers/net/tg3.h
Original file line number Diff line number Diff line change
Expand Up @@ -2174,6 +2174,7 @@ struct tg3 {
#define TG3_FLG2_ANY_SERDES (TG3_FLG2_PHY_SERDES | \
TG3_FLG2_MII_SERDES)
#define TG3_FLG2_PARALLEL_DETECT 0x01000000
#define TG3_FLG2_ICH_WORKAROUND 0x02000000

u32 split_mode_max_reqs;
#define SPLIT_MODE_5704_MAX_REQ 3
Expand Down

0 comments on commit 3c8dae4

Please sign in to comment.