Skip to content

Commit

Permalink
[TG3]: Add 5761 APE support
Browse files Browse the repository at this point in the history
This patch adds support for the new APE block, present in 5761 chips.
APE stands for Application Processing Engine.  The primary function of
the APE is to process manageability traffic, such as ASF.

Signed-off-by: Matt Carlson <mcarlson@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Matt Carlson authored and David S. Miller committed Oct 11, 2007
1 parent 6b91fa0 commit 0d3031d
Show file tree
Hide file tree
Showing 2 changed files with 274 additions and 4 deletions.
232 changes: 228 additions & 4 deletions drivers/net/tg3.c
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,16 @@ static u32 tg3_read32(struct tg3 *tp, u32 off)
return (readl(tp->regs + off));
}

static void tg3_ape_write32(struct tg3 *tp, u32 off, u32 val)
{
writel(val, tp->aperegs + off);
}

static u32 tg3_ape_read32(struct tg3 *tp, u32 off)
{
return (readl(tp->aperegs + off));
}

static void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val)
{
unsigned long flags;
Expand Down Expand Up @@ -500,6 +510,73 @@ static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val)
spin_unlock_irqrestore(&tp->indirect_lock, flags);
}

static void tg3_ape_lock_init(struct tg3 *tp)
{
int i;

/* Make sure the driver hasn't any stale locks. */
for (i = 0; i < 8; i++)
tg3_ape_write32(tp, TG3_APE_LOCK_GRANT + 4 * i,
APE_LOCK_GRANT_DRIVER);
}

static int tg3_ape_lock(struct tg3 *tp, int locknum)
{
int i, off;
int ret = 0;
u32 status;

if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
return 0;

switch (locknum) {
case TG3_APE_LOCK_MEM:
break;
default:
return -EINVAL;
}

off = 4 * locknum;

tg3_ape_write32(tp, TG3_APE_LOCK_REQ + off, APE_LOCK_REQ_DRIVER);

/* Wait for up to 1 millisecond to acquire lock. */
for (i = 0; i < 100; i++) {
status = tg3_ape_read32(tp, TG3_APE_LOCK_GRANT + off);
if (status == APE_LOCK_GRANT_DRIVER)
break;
udelay(10);
}

if (status != APE_LOCK_GRANT_DRIVER) {
/* Revoke the lock request. */
tg3_ape_write32(tp, TG3_APE_LOCK_GRANT + off,
APE_LOCK_GRANT_DRIVER);

ret = -EBUSY;
}

return ret;
}

static void tg3_ape_unlock(struct tg3 *tp, int locknum)
{
int off;

if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
return;

switch (locknum) {
case TG3_APE_LOCK_MEM:
break;
default:
return;
}

off = 4 * locknum;
tg3_ape_write32(tp, TG3_APE_LOCK_GRANT + off, APE_LOCK_GRANT_DRIVER);
}

static void tg3_disable_ints(struct tg3 *tp)
{
tw32(TG3PCI_MISC_HOST_CTRL,
Expand Down Expand Up @@ -1448,7 +1525,8 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
}

if (!(tp->tg3_flags & TG3_FLAG_WOL_ENABLE) &&
!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF))
!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF) &&
!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
tg3_power_down_phy(tp);

tg3_frob_aux_power(tp);
Expand Down Expand Up @@ -4726,6 +4804,80 @@ static void tg3_disable_nvram_access(struct tg3 *tp)
}
}

static void tg3_ape_send_event(struct tg3 *tp, u32 event)
{
int i;
u32 apedata;

apedata = tg3_ape_read32(tp, TG3_APE_SEG_SIG);
if (apedata != APE_SEG_SIG_MAGIC)
return;

apedata = tg3_ape_read32(tp, TG3_APE_FW_STATUS);
if (apedata != APE_FW_STATUS_READY)
return;

/* Wait for up to 1 millisecond for APE to service previous event. */
for (i = 0; i < 10; i++) {
if (tg3_ape_lock(tp, TG3_APE_LOCK_MEM))
return;

apedata = tg3_ape_read32(tp, TG3_APE_EVENT_STATUS);

if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING))
tg3_ape_write32(tp, TG3_APE_EVENT_STATUS,
event | APE_EVENT_STATUS_EVENT_PENDING);

tg3_ape_unlock(tp, TG3_APE_LOCK_MEM);

if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING))
break;

udelay(100);
}

if (!(apedata & APE_EVENT_STATUS_EVENT_PENDING))
tg3_ape_write32(tp, TG3_APE_EVENT, APE_EVENT_1);
}

static void tg3_ape_driver_state_change(struct tg3 *tp, int kind)
{
u32 event;
u32 apedata;

if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
return;

switch (kind) {
case RESET_KIND_INIT:
tg3_ape_write32(tp, TG3_APE_HOST_SEG_SIG,
APE_HOST_SEG_SIG_MAGIC);
tg3_ape_write32(tp, TG3_APE_HOST_SEG_LEN,
APE_HOST_SEG_LEN_MAGIC);
apedata = tg3_ape_read32(tp, TG3_APE_HOST_INIT_COUNT);
tg3_ape_write32(tp, TG3_APE_HOST_INIT_COUNT, ++apedata);
tg3_ape_write32(tp, TG3_APE_HOST_DRIVER_ID,
APE_HOST_DRIVER_ID_MAGIC);
tg3_ape_write32(tp, TG3_APE_HOST_BEHAVIOR,
APE_HOST_BEHAV_NO_PHYLOCK);

event = APE_EVENT_STATUS_STATE_START;
break;
case RESET_KIND_SHUTDOWN:
event = APE_EVENT_STATUS_STATE_UNLOAD;
break;
case RESET_KIND_SUSPEND:
event = APE_EVENT_STATUS_STATE_SUSPEND;
break;
default:
return;
}

event |= APE_EVENT_STATUS_DRIVER_EVNT | APE_EVENT_STATUS_STATE_CHNGE;

tg3_ape_send_event(tp, event);
}

/* tp->lock is held. */
static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind)
{
Expand Down Expand Up @@ -4753,6 +4905,10 @@ static void tg3_write_sig_pre_reset(struct tg3 *tp, int kind)
break;
};
}

if (kind == RESET_KIND_INIT ||
kind == RESET_KIND_SUSPEND)
tg3_ape_driver_state_change(tp, kind);
}

/* tp->lock is held. */
Expand All @@ -4774,6 +4930,9 @@ static void tg3_write_sig_post_reset(struct tg3 *tp, int kind)
break;
};
}

if (kind == RESET_KIND_SHUTDOWN)
tg3_ape_driver_state_change(tp, kind);
}

/* tp->lock is held. */
Expand Down Expand Up @@ -4864,6 +5023,10 @@ static void tg3_restore_pci_state(struct tg3 *tp)
if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 &&
(tp->tg3_flags & TG3_FLAG_PCIX_MODE))
val |= PCISTATE_RETRY_SAME_DMA;
/* Allow reads and writes to the APE register and memory space. */
if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)
val |= PCISTATE_ALLOW_APE_CTLSPC_WR |
PCISTATE_ALLOW_APE_SHMEM_WR;
pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val);

pci_write_config_dword(tp->pdev, TG3PCI_COMMAND, tp->pci_cmd);
Expand Down Expand Up @@ -5092,7 +5255,8 @@ static int tg3_chip_reset(struct tg3 *tp)
/* tp->lock is held. */
static void tg3_stop_fw(struct tg3 *tp)
{
if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) &&
!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) {
u32 val;
int i;

Expand Down Expand Up @@ -6173,6 +6337,16 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
tw32(TG3PCI_PCISTATE, val);
}

if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) {
/* Allow reads and writes to the
* APE register and memory space.
*/
val = tr32(TG3PCI_PCISTATE);
val |= PCISTATE_ALLOW_APE_CTLSPC_WR |
PCISTATE_ALLOW_APE_SHMEM_WR;
tw32(TG3PCI_PCISTATE, val);
}

if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5704_BX) {
/* Enable some hw fixes. */
val = tr32(TG3PCI_MSI_DATA);
Expand Down Expand Up @@ -6780,6 +6954,10 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
break;
};

/* Write our heartbeat update interval to APE. */
tg3_ape_write32(tp, TG3_APE_HOST_HEARTBEAT_INT_MS,
APE_HOST_HEARTBEAT_INT_DISABLE);

tg3_write_sig_post_reset(tp, RESET_KIND_INIT);

return 0;
Expand Down Expand Up @@ -10302,6 +10480,8 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)
tp->tg3_flags2 |= TG3_FLG2_ASF_NEW_HANDSHAKE;
}
if (nic_cfg & NIC_SRAM_DATA_CFG_APE_ENABLE)
tp->tg3_flags3 |= TG3_FLG3_ENABLE_APE;
if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES &&
!(nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL))
tp->tg3_flags &= ~TG3_FLAG_WOL_CAP;
Expand Down Expand Up @@ -10334,7 +10514,8 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
* firwmare access to the PHY hardware.
*/
err = 0;
if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) ||
(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) {
hw_phy_id = hw_phy_id_masked = PHY_ID_INVALID;
} else {
/* Now read the physical PHY_ID from the chip and verify
Expand Down Expand Up @@ -10381,6 +10562,7 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
}

if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) &&
!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) &&
!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) {
u32 bmsr, adv_reg, tg3_ctrl, mask;

Expand Down Expand Up @@ -10972,6 +11154,16 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
*/
tg3_get_eeprom_hw_cfg(tp);

if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) {
/* Allow reads and writes to the
* APE register and memory space.
*/
pci_state_reg |= PCISTATE_ALLOW_APE_CTLSPC_WR |
PCISTATE_ALLOW_APE_SHMEM_WR;
pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE,
pci_state_reg);
}

if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784)
tp->tg3_flags |= TG3_FLAG_CPMU_PRESENT;

Expand Down Expand Up @@ -12165,13 +12357,35 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,

tg3_init_coal(tp);

if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) {
if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) {
printk(KERN_ERR PFX "Cannot find proper PCI device "
"base address for APE, aborting.\n");
err = -ENODEV;
goto err_out_iounmap;
}

tg3reg_base = pci_resource_start(pdev, 2);
tg3reg_len = pci_resource_len(pdev, 2);

tp->aperegs = ioremap_nocache(tg3reg_base, tg3reg_len);
if (tp->aperegs == 0UL) {
printk(KERN_ERR PFX "Cannot map APE registers, "
"aborting.\n");
err = -ENOMEM;
goto err_out_iounmap;
}

tg3_ape_lock_init(tp);
}

pci_set_drvdata(pdev, dev);

err = register_netdev(dev);
if (err) {
printk(KERN_ERR PFX "Cannot register net device, "
"aborting.\n");
goto err_out_iounmap;
goto err_out_apeunmap;
}

printk(KERN_INFO "%s: Tigon3 [partno(%s) rev %04x PHY(%s)] (%s) %s Ethernet ",
Expand Down Expand Up @@ -12204,6 +12418,12 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,

return 0;

err_out_apeunmap:
if (tp->aperegs) {
iounmap(tp->aperegs);
tp->aperegs = NULL;
}

err_out_iounmap:
if (tp->regs) {
iounmap(tp->regs);
Expand Down Expand Up @@ -12231,6 +12451,10 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev)

flush_scheduled_work();
unregister_netdev(dev);
if (tp->aperegs) {
iounmap(tp->aperegs);
tp->aperegs = NULL;
}
if (tp->regs) {
iounmap(tp->regs);
tp->regs = NULL;
Expand Down
Loading

0 comments on commit 0d3031d

Please sign in to comment.