Skip to content

Commit

Permalink
sky2: handle descriptor errors
Browse files Browse the repository at this point in the history
There should never be descriptor error unless hardware or driver is buggy.
But if an error occurs, print useful information, clear irq, and recover.

Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
  • Loading branch information
Stephen Hemminger authored and Jeff Garzik committed Apr 19, 2007
1 parent 0a17e4c commit 40b0172
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 31 deletions.
67 changes: 36 additions & 31 deletions drivers/net/sky2.c
Original file line number Diff line number Diff line change
Expand Up @@ -2343,26 +2343,22 @@ static void sky2_mac_intr(struct sky2_hw *hw, unsigned port)
}
}

/* This should never happen it is a fatal situation */
static void sky2_descriptor_error(struct sky2_hw *hw, unsigned port,
const char *rxtx, u32 mask)
/* This should never happen it is a bug. */
static void sky2_le_error(struct sky2_hw *hw, unsigned port,
u16 q, unsigned ring_size)
{
struct net_device *dev = hw->dev[port];
struct sky2_port *sky2 = netdev_priv(dev);
u32 imask;

printk(KERN_ERR PFX "%s: %s descriptor error (hardware problem)\n",
dev ? dev->name : "<not registered>", rxtx);
unsigned idx;
const u64 *le = (q == Q_R1 || q == Q_R2)
? (u64 *) sky2->rx_le : (u64 *) sky2->tx_le;

imask = sky2_read32(hw, B0_IMSK);
imask &= ~mask;
sky2_write32(hw, B0_IMSK, imask);
idx = sky2_read16(hw, Y2_QADDR(q, PREF_UNIT_GET_IDX));
printk(KERN_ERR PFX "%s: descriptor error q=%#x get=%u [%llx] put=%u\n",
dev->name, (unsigned) q, idx, (unsigned long long) le[idx],
(unsigned) sky2_read16(hw, Y2_QADDR(q, PREF_UNIT_PUT_IDX)));

if (dev) {
spin_lock(&sky2->phy_lock);
sky2_link_down(sky2);
spin_unlock(&sky2->phy_lock);
}
sky2_write32(hw, Q_ADDR(q, Q_CSR), BMU_CLR_IRQ_CHK);
}

/* If idle then force a fake soft NAPI poll once a second
Expand All @@ -2386,40 +2382,49 @@ static void sky2_idle(unsigned long arg)
mod_timer(&hw->idle_timer, jiffies + msecs_to_jiffies(idle_timeout));
}


static int sky2_poll(struct net_device *dev0, int *budget)
/* Hardware/software error handling */
static void sky2_err_intr(struct sky2_hw *hw, u32 status)
{
struct sky2_hw *hw = ((struct sky2_port *) netdev_priv(dev0))->hw;
int work_limit = min(dev0->quota, *budget);
int work_done = 0;
u32 status = sky2_read32(hw, B0_Y2_SP_EISR);
if (net_ratelimit())
dev_warn(&hw->pdev->dev, "error interrupt status=%#x\n", status);

if (status & Y2_IS_HW_ERR)
sky2_hw_intr(hw);

if (status & Y2_IS_IRQ_PHY1)
sky2_phy_intr(hw, 0);

if (status & Y2_IS_IRQ_PHY2)
sky2_phy_intr(hw, 1);

if (status & Y2_IS_IRQ_MAC1)
sky2_mac_intr(hw, 0);

if (status & Y2_IS_IRQ_MAC2)
sky2_mac_intr(hw, 1);

if (status & Y2_IS_CHK_RX1)
sky2_descriptor_error(hw, 0, "receive", Y2_IS_CHK_RX1);
sky2_le_error(hw, 0, Q_R1, RX_LE_SIZE);

if (status & Y2_IS_CHK_RX2)
sky2_descriptor_error(hw, 1, "receive", Y2_IS_CHK_RX2);
sky2_le_error(hw, 1, Q_R2, RX_LE_SIZE);

if (status & Y2_IS_CHK_TXA1)
sky2_descriptor_error(hw, 0, "transmit", Y2_IS_CHK_TXA1);
sky2_le_error(hw, 0, Q_XA1, TX_RING_SIZE);

if (status & Y2_IS_CHK_TXA2)
sky2_descriptor_error(hw, 1, "transmit", Y2_IS_CHK_TXA2);
sky2_le_error(hw, 1, Q_XA2, TX_RING_SIZE);
}

static int sky2_poll(struct net_device *dev0, int *budget)
{
struct sky2_hw *hw = ((struct sky2_port *) netdev_priv(dev0))->hw;
int work_limit = min(dev0->quota, *budget);
int work_done = 0;
u32 status = sky2_read32(hw, B0_Y2_SP_EISR);

if (unlikely(status & Y2_IS_ERROR))
sky2_err_intr(hw, status);

if (status & Y2_IS_IRQ_PHY1)
sky2_phy_intr(hw, 0);

if (status & Y2_IS_IRQ_PHY2)
sky2_phy_intr(hw, 1);

work_done = sky2_status_intr(hw, work_limit);
if (work_done < work_limit) {
Expand Down
3 changes: 3 additions & 0 deletions drivers/net/sky2.h
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,9 @@ enum {
| Y2_IS_CHK_TXA1 | Y2_IS_CHK_RX1,
Y2_IS_PORT_2 = Y2_IS_IRQ_PHY2 | Y2_IS_IRQ_MAC2
| Y2_IS_CHK_TXA2 | Y2_IS_CHK_RX2,
Y2_IS_ERROR = Y2_IS_HW_ERR |
Y2_IS_IRQ_MAC1 | Y2_IS_CHK_TXA1 | Y2_IS_CHK_RX1 |
Y2_IS_IRQ_MAC2 | Y2_IS_CHK_TXA2 | Y2_IS_CHK_RX2,
};

/* B2_IRQM_HWE_MSK 32 bit IRQ Moderation HW Error Mask */
Expand Down

0 comments on commit 40b0172

Please sign in to comment.