Commit e07b1aa8 authored by Stephen Hemminger's avatar Stephen Hemminger Committed by Jeff Garzik

[PATCH] sky2: rework of NAPI and IRQ management

Redo the interupt handling of sky2 driver based on the IRQ mangement
documentation. All interrupts are handled by the device0 NAPI poll
routine.

Don't need to adjust interrupt mask in IRQ context, done only when
changing device under RTNL. Therefore don't need hwlock anymore.
Signed-off-by: default avatarStephen Hemminger <shemminger@osdl.org>
Signed-off-by: default avatarJeff Garzik <jeff@garzik.org>
parent c4b1580e
...@@ -500,9 +500,9 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port) ...@@ -500,9 +500,9 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
/* Force a renegotiation */ /* Force a renegotiation */
static void sky2_phy_reinit(struct sky2_port *sky2) static void sky2_phy_reinit(struct sky2_port *sky2)
{ {
down(&sky2->phy_sema); spin_lock_bh(&sky2->phy_lock);
sky2_phy_init(sky2->hw, sky2->port); sky2_phy_init(sky2->hw, sky2->port);
up(&sky2->phy_sema); spin_unlock_bh(&sky2->phy_lock);
} }
static void sky2_mac_init(struct sky2_hw *hw, unsigned port) static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
...@@ -567,9 +567,9 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port) ...@@ -567,9 +567,9 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
sky2_read16(hw, SK_REG(port, GMAC_IRQ_SRC)); sky2_read16(hw, SK_REG(port, GMAC_IRQ_SRC));
down(&sky2->phy_sema); spin_lock_bh(&sky2->phy_lock);
sky2_phy_init(hw, port); sky2_phy_init(hw, port);
up(&sky2->phy_sema); spin_unlock_bh(&sky2->phy_lock);
/* MIB clear */ /* MIB clear */
reg = gma_read16(hw, port, GM_PHY_ADDR); reg = gma_read16(hw, port, GM_PHY_ADDR);
...@@ -856,9 +856,9 @@ static int sky2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ...@@ -856,9 +856,9 @@ static int sky2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
case SIOCGMIIREG: { case SIOCGMIIREG: {
u16 val = 0; u16 val = 0;
down(&sky2->phy_sema); spin_lock_bh(&sky2->phy_lock);
err = __gm_phy_read(hw, sky2->port, data->reg_num & 0x1f, &val); err = __gm_phy_read(hw, sky2->port, data->reg_num & 0x1f, &val);
up(&sky2->phy_sema); spin_unlock_bh(&sky2->phy_lock);
data->val_out = val; data->val_out = val;
break; break;
...@@ -868,10 +868,10 @@ static int sky2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ...@@ -868,10 +868,10 @@ static int sky2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (!capable(CAP_NET_ADMIN)) if (!capable(CAP_NET_ADMIN))
return -EPERM; return -EPERM;
down(&sky2->phy_sema); spin_lock_bh(&sky2->phy_lock);
err = gm_phy_write(hw, sky2->port, data->reg_num & 0x1f, err = gm_phy_write(hw, sky2->port, data->reg_num & 0x1f,
data->val_in); data->val_in);
up(&sky2->phy_sema); spin_unlock_bh(&sky2->phy_lock);
break; break;
} }
return err; return err;
...@@ -983,7 +983,7 @@ static int sky2_up(struct net_device *dev) ...@@ -983,7 +983,7 @@ static int sky2_up(struct net_device *dev)
struct sky2_port *sky2 = netdev_priv(dev); struct sky2_port *sky2 = netdev_priv(dev);
struct sky2_hw *hw = sky2->hw; struct sky2_hw *hw = sky2->hw;
unsigned port = sky2->port; unsigned port = sky2->port;
u32 ramsize, rxspace; u32 ramsize, rxspace, imask;
int err = -ENOMEM; int err = -ENOMEM;
if (netif_msg_ifup(sky2)) if (netif_msg_ifup(sky2))
...@@ -1048,10 +1048,10 @@ static int sky2_up(struct net_device *dev) ...@@ -1048,10 +1048,10 @@ static int sky2_up(struct net_device *dev)
goto err_out; goto err_out;
/* Enable interrupts from phy/mac for port */ /* Enable interrupts from phy/mac for port */
spin_lock_irq(&hw->hw_lock); imask = sky2_read32(hw, B0_IMSK);
hw->intr_mask |= (port == 0) ? Y2_IS_PORT_1 : Y2_IS_PORT_2; imask |= (port == 0) ? Y2_IS_PORT_1 : Y2_IS_PORT_2;
sky2_write32(hw, B0_IMSK, hw->intr_mask); sky2_write32(hw, B0_IMSK, imask);
spin_unlock_irq(&hw->hw_lock);
return 0; return 0;
err_out: err_out:
...@@ -1343,6 +1343,7 @@ static int sky2_down(struct net_device *dev) ...@@ -1343,6 +1343,7 @@ static int sky2_down(struct net_device *dev)
struct sky2_hw *hw = sky2->hw; struct sky2_hw *hw = sky2->hw;
unsigned port = sky2->port; unsigned port = sky2->port;
u16 ctrl; u16 ctrl;
u32 imask;
/* Never really got started! */ /* Never really got started! */
if (!sky2->tx_le) if (!sky2->tx_le)
...@@ -1354,14 +1355,6 @@ static int sky2_down(struct net_device *dev) ...@@ -1354,14 +1355,6 @@ static int sky2_down(struct net_device *dev)
/* Stop more packets from being queued */ /* Stop more packets from being queued */
netif_stop_queue(dev); netif_stop_queue(dev);
/* Disable port IRQ */
spin_lock_irq(&hw->hw_lock);
hw->intr_mask &= ~((sky2->port == 0) ? Y2_IS_IRQ_PHY1 : Y2_IS_IRQ_PHY2);
sky2_write32(hw, B0_IMSK, hw->intr_mask);
spin_unlock_irq(&hw->hw_lock);
flush_scheduled_work();
sky2_phy_reset(hw, port); sky2_phy_reset(hw, port);
/* Stop transmitter */ /* Stop transmitter */
...@@ -1405,6 +1398,11 @@ static int sky2_down(struct net_device *dev) ...@@ -1405,6 +1398,11 @@ static int sky2_down(struct net_device *dev)
sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET); sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_SET); sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_SET);
/* Disable port IRQ */
imask = sky2_read32(hw, B0_IMSK);
imask &= ~(sky2->port == 0) ? Y2_IS_PORT_1 : Y2_IS_PORT_2;
sky2_write32(hw, B0_IMSK, imask);
/* turn off LED's */ /* turn off LED's */
sky2_write16(hw, B0_Y2LED, LED_STAT_OFF); sky2_write16(hw, B0_Y2LED, LED_STAT_OFF);
...@@ -1599,20 +1597,19 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux) ...@@ -1599,20 +1597,19 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux)
return 0; return 0;
} }
/* /* Interrupt from PHY */
* Interrupt from PHY are handled outside of interrupt context static void sky2_phy_intr(struct sky2_hw *hw, unsigned port)
* because accessing phy registers requires spin wait which might
* cause excess interrupt latency.
*/
static void sky2_phy_task(void *arg)
{ {
struct sky2_port *sky2 = arg; struct net_device *dev = hw->dev[port];
struct sky2_hw *hw = sky2->hw; struct sky2_port *sky2 = netdev_priv(dev);
u16 istatus, phystat; u16 istatus, phystat;
down(&sky2->phy_sema); spin_lock(&sky2->phy_lock);
istatus = gm_phy_read(hw, sky2->port, PHY_MARV_INT_STAT); istatus = gm_phy_read(hw, port, PHY_MARV_INT_STAT);
phystat = gm_phy_read(hw, sky2->port, PHY_MARV_PHY_STAT); phystat = gm_phy_read(hw, port, PHY_MARV_PHY_STAT);
if (!netif_running(dev))
goto out;
if (netif_msg_intr(sky2)) if (netif_msg_intr(sky2))
printk(KERN_INFO PFX "%s: phy interrupt status 0x%x 0x%x\n", printk(KERN_INFO PFX "%s: phy interrupt status 0x%x 0x%x\n",
...@@ -1638,12 +1635,7 @@ static void sky2_phy_task(void *arg) ...@@ -1638,12 +1635,7 @@ static void sky2_phy_task(void *arg)
sky2_link_down(sky2); sky2_link_down(sky2);
} }
out: out:
up(&sky2->phy_sema); spin_unlock(&sky2->phy_lock);
spin_lock_irq(&hw->hw_lock);
hw->intr_mask |= (sky2->port == 0) ? Y2_IS_IRQ_PHY1 : Y2_IS_IRQ_PHY2;
sky2_write32(hw, B0_IMSK, hw->intr_mask);
spin_unlock_irq(&hw->hw_lock);
} }
...@@ -1655,20 +1647,6 @@ static void sky2_tx_timeout(struct net_device *dev) ...@@ -1655,20 +1647,6 @@ static void sky2_tx_timeout(struct net_device *dev)
struct sky2_port *sky2 = netdev_priv(dev); struct sky2_port *sky2 = netdev_priv(dev);
struct sky2_hw *hw = sky2->hw; struct sky2_hw *hw = sky2->hw;
unsigned txq = txqaddr[sky2->port]; unsigned txq = txqaddr[sky2->port];
u16 ridx;
/* Maybe we just missed an status interrupt */
spin_lock(&sky2->tx_lock);
ridx = sky2_read16(hw,
sky2->port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX);
sky2_tx_complete(sky2, ridx);
spin_unlock(&sky2->tx_lock);
if (!netif_queue_stopped(dev)) {
if (net_ratelimit())
pr_info(PFX "transmit interrupt missed? recovered\n");
return;
}
if (netif_msg_timer(sky2)) if (netif_msg_timer(sky2))
printk(KERN_ERR PFX "%s: tx timeout\n", dev->name); printk(KERN_ERR PFX "%s: tx timeout\n", dev->name);
...@@ -1698,6 +1676,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) ...@@ -1698,6 +1676,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
struct sky2_hw *hw = sky2->hw; struct sky2_hw *hw = sky2->hw;
int err; int err;
u16 ctl, mode; u16 ctl, mode;
u32 imask;
if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU) if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
return -EINVAL; return -EINVAL;
...@@ -1710,12 +1689,15 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) ...@@ -1710,12 +1689,15 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
return 0; return 0;
} }
imask = sky2_read32(hw, B0_IMSK);
sky2_write32(hw, B0_IMSK, 0); sky2_write32(hw, B0_IMSK, 0);
dev->trans_start = jiffies; /* prevent tx timeout */ dev->trans_start = jiffies; /* prevent tx timeout */
netif_stop_queue(dev); netif_stop_queue(dev);
netif_poll_disable(hw->dev[0]); netif_poll_disable(hw->dev[0]);
synchronize_irq(hw->pdev->irq);
ctl = gma_read16(hw, sky2->port, GM_GP_CTRL); ctl = gma_read16(hw, sky2->port, GM_GP_CTRL);
gma_write16(hw, sky2->port, GM_GP_CTRL, ctl & ~GM_GPCR_RX_ENA); gma_write16(hw, sky2->port, GM_GP_CTRL, ctl & ~GM_GPCR_RX_ENA);
sky2_rx_stop(sky2); sky2_rx_stop(sky2);
...@@ -1734,7 +1716,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu) ...@@ -1734,7 +1716,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
sky2_write8(hw, RB_ADDR(rxqaddr[sky2->port], RB_CTRL), RB_ENA_OP_MD); sky2_write8(hw, RB_ADDR(rxqaddr[sky2->port], RB_CTRL), RB_ENA_OP_MD);
err = sky2_rx_start(sky2); err = sky2_rx_start(sky2);
sky2_write32(hw, B0_IMSK, hw->intr_mask); sky2_write32(hw, B0_IMSK, imask);
if (err) if (err)
dev_close(dev); dev_close(dev);
...@@ -1838,76 +1820,51 @@ static struct sk_buff *sky2_receive(struct sky2_port *sky2, ...@@ -1838,76 +1820,51 @@ static struct sk_buff *sky2_receive(struct sky2_port *sky2,
goto resubmit; goto resubmit;
} }
/* /* Transmit complete */
* Check for transmit complete static inline void sky2_tx_done(struct net_device *dev, u16 last)
*/
#define TX_NO_STATUS 0xffff
static void sky2_tx_check(struct sky2_hw *hw, int port, u16 last)
{ {
if (last != TX_NO_STATUS) { struct sky2_port *sky2 = netdev_priv(dev);
struct net_device *dev = hw->dev[port];
if (dev && netif_running(dev)) {
struct sky2_port *sky2 = netdev_priv(dev);
spin_lock(&sky2->tx_lock); if (netif_running(dev)) {
sky2_tx_complete(sky2, last); spin_lock(&sky2->tx_lock);
spin_unlock(&sky2->tx_lock); sky2_tx_complete(sky2, last);
} spin_unlock(&sky2->tx_lock);
} }
} }
/* /* Process status response ring */
* Both ports share the same status interrupt, therefore there is only static int sky2_status_intr(struct sky2_hw *hw, int to_do)
* one poll routine.
*/
static int sky2_poll(struct net_device *dev0, int *budget)
{ {
struct sky2_hw *hw = ((struct sky2_port *) netdev_priv(dev0))->hw; int work_done = 0;
unsigned int to_do = min(dev0->quota, *budget);
unsigned int work_done = 0;
u16 hwidx;
u16 tx_done[2] = { TX_NO_STATUS, TX_NO_STATUS };
sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ);
/*
* Kick the STAT_LEV_TIMER_CTRL timer.
* This fixes my hangs on Yukon-EC (0xb6) rev 1.
* The if clause is there to start the timer only if it has been
* configured correctly and not been disabled via ethtool.
*/
if (sky2_read8(hw, STAT_LEV_TIMER_CTRL) == TIM_START) {
sky2_write8(hw, STAT_LEV_TIMER_CTRL, TIM_STOP);
sky2_write8(hw, STAT_LEV_TIMER_CTRL, TIM_START);
}
hwidx = sky2_read16(hw, STAT_PUT_IDX);
BUG_ON(hwidx >= STATUS_RING_SIZE);
rmb(); rmb();
while (hwidx != hw->st_idx) { for(;;) {
struct sky2_status_le *le = hw->st_le + hw->st_idx; struct sky2_status_le *le = hw->st_le + hw->st_idx;
struct net_device *dev; struct net_device *dev;
struct sky2_port *sky2; struct sky2_port *sky2;
struct sk_buff *skb; struct sk_buff *skb;
u32 status; u32 status;
u16 length; u16 length;
u8 link, opcode;
opcode = le->opcode;
if (!opcode)
break;
opcode &= ~HW_OWNER;
le = hw->st_le + hw->st_idx;
hw->st_idx = (hw->st_idx + 1) % STATUS_RING_SIZE; hw->st_idx = (hw->st_idx + 1) % STATUS_RING_SIZE;
prefetch(hw->st_le + hw->st_idx); le->opcode = 0;
BUG_ON(le->link >= 2); link = le->link;
dev = hw->dev[le->link]; BUG_ON(link >= 2);
if (dev == NULL || !netif_running(dev)) dev = hw->dev[link];
continue;
sky2 = netdev_priv(dev); sky2 = netdev_priv(dev);
status = le32_to_cpu(le->status); length = le->length;
length = le16_to_cpu(le->length); status = le->status;
switch (le->opcode & ~HW_OWNER) { switch (opcode) {
case OP_RXSTAT: case OP_RXSTAT:
skb = sky2_receive(sky2, length, status); skb = sky2_receive(sky2, length, status);
if (!skb) if (!skb)
...@@ -1947,42 +1904,23 @@ static int sky2_poll(struct net_device *dev0, int *budget) ...@@ -1947,42 +1904,23 @@ static int sky2_poll(struct net_device *dev0, int *budget)
case OP_TXINDEXLE: case OP_TXINDEXLE:
/* TX index reports status for both ports */ /* TX index reports status for both ports */
tx_done[0] = status & 0xffff; sky2_tx_done(hw->dev[0], status & 0xffff);
tx_done[1] = ((status >> 24) & 0xff) if (hw->dev[1])
| (u16)(length & 0xf) << 8; sky2_tx_done(hw->dev[1],
((status >> 24) & 0xff)
| (u16)(length & 0xf) << 8);
break; break;
default: default:
if (net_ratelimit()) if (net_ratelimit())
printk(KERN_WARNING PFX printk(KERN_WARNING PFX
"unknown status opcode 0x%x\n", le->opcode); "unknown status opcode 0x%x\n", opcode);
break; break;
} }
} }
exit_loop: exit_loop:
sky2_tx_check(hw, 0, tx_done[0]); return work_done;
sky2_tx_check(hw, 1, tx_done[1]);
if (sky2_read8(hw, STAT_TX_TIMER_CTRL) == TIM_START) {
sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP);
sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START);
}
if (likely(work_done < to_do)) {
spin_lock_irq(&hw->hw_lock);
__netif_rx_complete(dev0);
hw->intr_mask |= Y2_IS_STAT_BMU;
sky2_write32(hw, B0_IMSK, hw->intr_mask);
spin_unlock_irq(&hw->hw_lock);
return 0;
} else {
*budget -= work_done;
dev0->quota -= work_done;
return 1;
}
} }
static void sky2_hw_error(struct sky2_hw *hw, unsigned port, u32 status) static void sky2_hw_error(struct sky2_hw *hw, unsigned port, u32 status)
...@@ -2101,42 +2039,17 @@ static void sky2_mac_intr(struct sky2_hw *hw, unsigned port) ...@@ -2101,42 +2039,17 @@ static void sky2_mac_intr(struct sky2_hw *hw, unsigned port)
} }
} }
static void sky2_phy_intr(struct sky2_hw *hw, unsigned port)
{
struct net_device *dev = hw->dev[port];
struct sky2_port *sky2 = netdev_priv(dev);
hw->intr_mask &= ~(port == 0 ? Y2_IS_IRQ_PHY1 : Y2_IS_IRQ_PHY2);
sky2_write32(hw, B0_IMSK, hw->intr_mask);
schedule_work(&sky2->phy_task);
}
static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs) static int sky2_poll(struct net_device *dev0, int *budget)
{ {
struct sky2_hw *hw = dev_id; struct sky2_hw *hw = ((struct sky2_port *) netdev_priv(dev0))->hw;
struct net_device *dev0 = hw->dev[0]; int work_limit = min(dev0->quota, *budget);
u32 status; int work_done = 0;
u32 status = sky2_read32(hw, B0_ISRC);
status = sky2_read32(hw, B0_Y2_SP_ISRC2);
if (status == 0 || status == ~0)
return IRQ_NONE;
spin_lock(&hw->hw_lock);
if (status & Y2_IS_HW_ERR) if (status & Y2_IS_HW_ERR)
sky2_hw_intr(hw); sky2_hw_intr(hw);
/* Do NAPI for Rx and Tx status */
if (status & Y2_IS_STAT_BMU) {
hw->intr_mask &= ~Y2_IS_STAT_BMU;
sky2_write32(hw, B0_IMSK, hw->intr_mask);
if (likely(__netif_rx_schedule_prep(dev0))) {
prefetch(&hw->st_le[hw->st_idx]);
__netif_rx_schedule(dev0);
}
}
if (status & Y2_IS_IRQ_PHY1) if (status & Y2_IS_IRQ_PHY1)
sky2_phy_intr(hw, 0); sky2_phy_intr(hw, 0);
...@@ -2149,9 +2062,38 @@ static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs) ...@@ -2149,9 +2062,38 @@ static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs)
if (status & Y2_IS_IRQ_MAC2) if (status & Y2_IS_IRQ_MAC2)
sky2_mac_intr(hw, 1); sky2_mac_intr(hw, 1);
if (status & Y2_IS_STAT_BMU) {
work_done = sky2_status_intr(hw, work_limit);
*budget -= work_done;
dev0->quota -= work_done;
if (work_done >= work_limit)
return 1;
sky2_write32(hw, STAT_CTRL, SC_STAT_CLR_IRQ);
}
netif_rx_complete(dev0);
/* Ack interrupt and re-enable */
sky2_write32(hw, B0_Y2_SP_ICR, 2); sky2_write32(hw, B0_Y2_SP_ICR, 2);
return 0;
}
static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs)
{
struct sky2_hw *hw = dev_id;
struct net_device *dev0 = hw->dev[0];
u32 status;
/* Reading this mask interrupts as side effect */
status = sky2_read32(hw, B0_Y2_SP_ISRC2);
if (status == 0 || status == ~0)
return IRQ_NONE;
spin_unlock(&hw->hw_lock); prefetch(&hw->st_le[hw->st_idx]);
if (likely(__netif_rx_schedule_prep(dev0)))
__netif_rx_schedule(dev0);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -2320,7 +2262,6 @@ static int sky2_reset(struct sky2_hw *hw) ...@@ -2320,7 +2262,6 @@ static int sky2_reset(struct sky2_hw *hw)
/* Set the list last index */ /* Set the list last index */
sky2_write16(hw, STAT_LAST_IDX, STATUS_RING_SIZE - 1); sky2_write16(hw, STAT_LAST_IDX, STATUS_RING_SIZE - 1);
/* These status setup values are copied from SysKonnect's driver */
sky2_write16(hw, STAT_TX_IDX_TH, 10); sky2_write16(hw, STAT_TX_IDX_TH, 10);
sky2_write8(hw, STAT_FIFO_WM, 16); sky2_write8(hw, STAT_FIFO_WM, 16);
...@@ -2714,7 +2655,7 @@ static int sky2_phys_id(struct net_device *dev, u32 data) ...@@ -2714,7 +2655,7 @@ static int sky2_phys_id(struct net_device *dev, u32 data)
ms = data * 1000; ms = data * 1000;
/* save initial values */ /* save initial values */
down(&sky2->phy_sema); spin_lock_bh(&sky2->phy_lock);
if (hw->chip_id == CHIP_ID_YUKON_XL) { if (hw->chip_id == CHIP_ID_YUKON_XL) {
u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR); u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3); gm_phy_write(hw, port, PHY_MARV_EXT_ADR, 3);
...@@ -2730,9 +2671,9 @@ static int sky2_phys_id(struct net_device *dev, u32 data) ...@@ -2730,9 +2671,9 @@ static int sky2_phys_id(struct net_device *dev, u32 data)
sky2_led(hw, port, onoff); sky2_led(hw, port, onoff);
onoff = !onoff; onoff = !onoff;
up(&sky2->phy_sema); spin_unlock_bh(&sky2->phy_lock);
interrupted = msleep_interruptible(250); interrupted = msleep_interruptible(250);
down(&sky2->phy_sema); spin_lock_bh(&sky2->phy_lock);
ms -= 250; ms -= 250;
} }
...@@ -2747,7 +2688,7 @@ static int sky2_phys_id(struct net_device *dev, u32 data) ...@@ -2747,7 +2688,7 @@ static int sky2_phys_id(struct net_device *dev, u32 data)
gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl); gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl);
gm_phy_write(hw, port, PHY_MARV_LED_OVER, ledover); gm_phy_write(hw, port, PHY_MARV_LED_OVER, ledover);
} }
up(&sky2->phy_sema); spin_unlock_bh(&sky2->phy_lock);
return 0; return 0;
} }
...@@ -3023,8 +2964,7 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, ...@@ -3023,8 +2964,7 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
*/ */
sky2->rx_csum = (hw->chip_id != CHIP_ID_YUKON_XL); sky2->rx_csum = (hw->chip_id != CHIP_ID_YUKON_XL);
INIT_WORK(&sky2->phy_task, sky2_phy_task, sky2); spin_lock_init(&sky2->phy_lock);
init_MUTEX(&sky2->phy_sema);
sky2->tx_pending = TX_DEF_PENDING; sky2->tx_pending = TX_DEF_PENDING;
sky2->rx_pending = RX_DEF_PENDING; sky2->rx_pending = RX_DEF_PENDING;
sky2->rx_bufsize = sky2_buf_size(ETH_DATA_LEN); sky2->rx_bufsize = sky2_buf_size(ETH_DATA_LEN);
...@@ -3136,7 +3076,6 @@ static int __devinit sky2_probe(struct pci_dev *pdev, ...@@ -3136,7 +3076,6 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
goto err_out_free_hw; goto err_out_free_hw;
} }
hw->pm_cap = pm_cap; hw->pm_cap = pm_cap;
spin_lock_init(&hw->hw_lock);
#ifdef __BIG_ENDIAN #ifdef __BIG_ENDIAN
/* byte swap descriptors in hardware */ /* byte swap descriptors in hardware */
...@@ -3196,8 +3135,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev, ...@@ -3196,8 +3135,7 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
goto err_out_unregister; goto err_out_unregister;
} }
hw->intr_mask = Y2_IS_BASE; sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
sky2_write32(hw, B0_IMSK, hw->intr_mask);
pci_set_drvdata(pdev, hw); pci_set_drvdata(pdev, hw);
......
...@@ -278,13 +278,9 @@ enum { ...@@ -278,13 +278,9 @@ enum {
Y2_IS_CHK_TXS1 = 1<<1, /* Descriptor error TXS 1 */ Y2_IS_CHK_TXS1 = 1<<1, /* Descriptor error TXS 1 */
Y2_IS_CHK_TXA1 = 1<<0, /* Descriptor error TXA 1 */ Y2_IS_CHK_TXA1 = 1<<0, /* Descriptor error TXA 1 */
Y2_IS_BASE = Y2_IS_HW_ERR | Y2_IS_STAT_BMU | Y2_IS_BASE = Y2_IS_HW_ERR | Y2_IS_STAT_BMU,
Y2_IS_POLL_CHK | Y2_IS_TWSI_RDY | Y2_IS_PORT_1 = Y2_IS_IRQ_PHY1 | Y2_IS_IRQ_MAC1,
Y2_IS_IRQ_SW | Y2_IS_TIMINT, Y2_IS_PORT_2 = Y2_IS_IRQ_PHY2 | Y2_IS_IRQ_MAC2,
Y2_IS_PORT_1 = Y2_IS_IRQ_PHY1 | Y2_IS_IRQ_MAC1 |
Y2_IS_CHK_RX1 | Y2_IS_CHK_TXA1 | Y2_IS_CHK_TXS1,
Y2_IS_PORT_2 = Y2_IS_IRQ_PHY2 | Y2_IS_IRQ_MAC2 |
Y2_IS_CHK_RX2 | Y2_IS_CHK_TXA2 | Y2_IS_CHK_TXS2,
}; };
/* B2_IRQM_HWE_MSK 32 bit IRQ Moderation HW Error Mask */ /* B2_IRQM_HWE_MSK 32 bit IRQ Moderation HW Error Mask */
...@@ -1832,6 +1828,7 @@ struct sky2_port { ...@@ -1832,6 +1828,7 @@ struct sky2_port {
struct net_device *netdev; struct net_device *netdev;
unsigned port; unsigned port;
u32 msg_enable; u32 msg_enable;
spinlock_t phy_lock;
spinlock_t tx_lock ____cacheline_aligned_in_smp; spinlock_t tx_lock ____cacheline_aligned_in_smp;
struct tx_ring_info *tx_ring; struct tx_ring_info *tx_ring;
...@@ -1866,16 +1863,12 @@ struct sky2_port { ...@@ -1866,16 +1863,12 @@ struct sky2_port {
struct net_device_stats net_stats; struct net_device_stats net_stats;
struct work_struct phy_task;
struct semaphore phy_sema;
}; };
struct sky2_hw { struct sky2_hw {
void __iomem *regs; void __iomem *regs;
struct pci_dev *pdev; struct pci_dev *pdev;
struct net_device *dev[2]; struct net_device *dev[2];
spinlock_t hw_lock;
u32 intr_mask;
int pm_cap; int pm_cap;
u8 chip_id; u8 chip_id;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment