Skip to content

Commit a9e9fd7

Browse files
Stephen Hemmingerdavem330
authored andcommitted
skge: handle irq better on single port card
Most boards with SysKonnect/Marvell Ethernet have only a single port. For the single port case, use the standard Ethernet driver convention of allocating IRQ when device is brought up rather than at probe time. This patch also adds some additional read after writes to avoid any PCI posting problems when setting the IRQ mask. The error handling of dual port cards is also changed. If second port can not be brought up, then just fail. No point in continuing, since the failure is most certainly because of out of memory. It is worth noting that the dual port skge device has a single irq but two seperate status rings and therefore has two NAPI objects, one for each port. Signed-off-by: Stephen Hemminger <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 04b7117 commit a9e9fd7

File tree

1 file changed

+52
-20
lines changed
  • drivers/net/ethernet/marvell

1 file changed

+52
-20
lines changed

drivers/net/ethernet/marvell/skge.c

Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ static void yukon_init(struct skge_hw *hw, int port);
113113
static void genesis_mac_init(struct skge_hw *hw, int port);
114114
static void genesis_link_up(struct skge_port *skge);
115115
static void skge_set_multicast(struct net_device *dev);
116+
static irqreturn_t skge_intr(int irq, void *dev_id);
116117

117118
/* Avoid conditionals by using array */
118119
static const int txqaddr[] = { Q_XA1, Q_XA2 };
@@ -2568,6 +2569,16 @@ static int skge_up(struct net_device *dev)
25682569
if (err)
25692570
goto free_rx_ring;
25702571

2572+
if (hw->ports == 1) {
2573+
err = request_irq(hw->pdev->irq, skge_intr, IRQF_SHARED,
2574+
dev->name, hw);
2575+
if (err) {
2576+
netdev_err(dev, "Unable to allocate interrupt %d error: %d\n",
2577+
hw->pdev->irq, err);
2578+
goto free_tx_ring;
2579+
}
2580+
}
2581+
25712582
/* Initialize MAC */
25722583
spin_lock_bh(&hw->phy_lock);
25732584
if (is_genesis(hw))
@@ -2595,11 +2606,14 @@ static int skge_up(struct net_device *dev)
25952606
spin_lock_irq(&hw->hw_lock);
25962607
hw->intr_mask |= portmask[port];
25972608
skge_write32(hw, B0_IMSK, hw->intr_mask);
2609+
skge_read32(hw, B0_IMSK);
25982610
spin_unlock_irq(&hw->hw_lock);
25992611

26002612
napi_enable(&skge->napi);
26012613
return 0;
26022614

2615+
free_tx_ring:
2616+
kfree(skge->tx_ring.start);
26032617
free_rx_ring:
26042618
skge_rx_clean(skge);
26052619
kfree(skge->rx_ring.start);
@@ -2640,9 +2654,13 @@ static int skge_down(struct net_device *dev)
26402654

26412655
spin_lock_irq(&hw->hw_lock);
26422656
hw->intr_mask &= ~portmask[port];
2643-
skge_write32(hw, B0_IMSK, hw->intr_mask);
2657+
skge_write32(hw, B0_IMSK, (hw->ports == 1) ? 0 : hw->intr_mask);
2658+
skge_read32(hw, B0_IMSK);
26442659
spin_unlock_irq(&hw->hw_lock);
26452660

2661+
if (hw->ports == 1)
2662+
free_irq(hw->pdev->irq, hw);
2663+
26462664
skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), LED_OFF);
26472665
if (is_genesis(hw))
26482666
genesis_stop(skge);
@@ -3603,7 +3621,8 @@ static int skge_reset(struct skge_hw *hw)
36033621
skge_write32(hw, B2_IRQM_INI, skge_usecs2clk(hw, 100));
36043622
skge_write32(hw, B2_IRQM_CTRL, TIM_START);
36053623

3606-
skge_write32(hw, B0_IMSK, hw->intr_mask);
3624+
/* Leave irq disabled until first port is brought up. */
3625+
skge_write32(hw, B0_IMSK, 0);
36073626

36083627
for (i = 0; i < hw->ports; i++) {
36093628
if (is_genesis(hw))
@@ -3930,31 +3949,39 @@ static int __devinit skge_probe(struct pci_dev *pdev,
39303949
goto err_out_free_netdev;
39313950
}
39323951

3933-
err = request_irq(pdev->irq, skge_intr, IRQF_SHARED, hw->irq_name, hw);
3934-
if (err) {
3935-
dev_err(&pdev->dev, "%s: cannot assign irq %d\n",
3936-
dev->name, pdev->irq);
3937-
goto err_out_unregister;
3938-
}
39393952
skge_show_addr(dev);
39403953

39413954
if (hw->ports > 1) {
39423955
dev1 = skge_devinit(hw, 1, using_dac);
3943-
if (dev1 && register_netdev(dev1) == 0)
3944-
skge_show_addr(dev1);
3945-
else {
3946-
/* Failure to register second port need not be fatal */
3947-
dev_warn(&pdev->dev, "register of second port failed\n");
3948-
hw->dev[1] = NULL;
3949-
hw->ports = 1;
3950-
if (dev1)
3951-
free_netdev(dev1);
3956+
if (!dev1) {
3957+
err = -ENOMEM;
3958+
goto err_out_unregister;
39523959
}
3960+
3961+
err = register_netdev(dev1);
3962+
if (err) {
3963+
dev_err(&pdev->dev, "cannot register second net device\n");
3964+
goto err_out_free_dev1;
3965+
}
3966+
3967+
err = request_irq(pdev->irq, skge_intr, IRQF_SHARED,
3968+
hw->irq_name, hw);
3969+
if (err) {
3970+
dev_err(&pdev->dev, "cannot assign irq %d\n",
3971+
pdev->irq);
3972+
goto err_out_unregister_dev1;
3973+
}
3974+
3975+
skge_show_addr(dev1);
39533976
}
39543977
pci_set_drvdata(pdev, hw);
39553978

39563979
return 0;
39573980

3981+
err_out_unregister_dev1:
3982+
unregister_netdev(dev1);
3983+
err_out_free_dev1:
3984+
free_netdev(dev1);
39583985
err_out_unregister:
39593986
unregister_netdev(dev);
39603987
err_out_free_netdev:
@@ -3992,14 +4019,19 @@ static void __devexit skge_remove(struct pci_dev *pdev)
39924019

39934020
spin_lock_irq(&hw->hw_lock);
39944021
hw->intr_mask = 0;
3995-
skge_write32(hw, B0_IMSK, 0);
3996-
skge_read32(hw, B0_IMSK);
4022+
4023+
if (hw->ports > 1) {
4024+
skge_write32(hw, B0_IMSK, 0);
4025+
skge_read32(hw, B0_IMSK);
4026+
free_irq(pdev->irq, hw);
4027+
}
39974028
spin_unlock_irq(&hw->hw_lock);
39984029

39994030
skge_write16(hw, B0_LED, LED_STAT_OFF);
40004031
skge_write8(hw, B0_CTST, CS_RST_SET);
40014032

4002-
free_irq(pdev->irq, hw);
4033+
if (hw->ports > 1)
4034+
free_irq(pdev->irq, hw);
40034035
pci_release_regions(pdev);
40044036
pci_disable_device(pdev);
40054037
if (dev1)

0 commit comments

Comments
 (0)