sky2: Make sure both ports initialize correctly
[sfrench/cifs-2.6.git] / drivers / net / sky2.c
index ba5180a2326456d8731fdd33e47494bf7323ef99..4bb52e9cd371afc58db9e8620bf8a3182643f686 100644 (file)
@@ -65,8 +65,8 @@
 #define RX_DEF_PENDING         RX_MAX_PENDING
 
 /* This is the worst case number of transmit list elements for a single skb:
-   VLAN + TSO + CKSUM + Data + skb_frags * DMA */
-#define MAX_SKB_TX_LE  (4 + (sizeof(dma_addr_t)/sizeof(u32))*MAX_SKB_FRAGS)
+   VLAN:GSO + CKSUM + Data + skb_frags * DMA */
+#define MAX_SKB_TX_LE  (2 + (sizeof(dma_addr_t)/sizeof(u32))*(MAX_SKB_FRAGS+1))
 #define TX_MIN_PENDING         (MAX_SKB_TX_LE+1)
 #define TX_MAX_PENDING         4096
 #define TX_DEF_PENDING         127
@@ -272,8 +272,9 @@ static void sky2_power_aux(struct sky2_hw *hw)
                            Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
                            Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS);
 
-       /* switch power to VAUX */
-       if (sky2_read16(hw, B0_CTST) & Y2_VAUX_AVAIL)
+       /* switch power to VAUX if supported and PME from D3cold */
+       if ( (sky2_read32(hw, B0_CTST) & Y2_VAUX_AVAIL) &&
+            pci_pme_capable(hw->pdev, PCI_D3cold))
                sky2_write8(hw, B0_POWER_CTRL,
                            (PC_VAUX_ENA | PC_VCC_ENA |
                             PC_VAUX_ON | PC_VCC_OFF));
@@ -1213,9 +1214,6 @@ static int sky2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        }
 
        case SIOCSMIIREG:
-               if (!capable(CAP_NET_ADMIN))
-                       return -EPERM;
-
                spin_lock_bh(&sky2->phy_lock);
                err = gm_phy_write(hw, sky2->port, data->reg_num & 0x1f,
                                   data->val_in);
@@ -1405,6 +1403,61 @@ nomem:
        return -ENOMEM;
 }
 
+static int sky2_alloc_buffers(struct sky2_port *sky2)
+{
+       struct sky2_hw *hw = sky2->hw;
+
+       /* must be power of 2 */
+       sky2->tx_le = pci_alloc_consistent(hw->pdev,
+                                          sky2->tx_ring_size *
+                                          sizeof(struct sky2_tx_le),
+                                          &sky2->tx_le_map);
+       if (!sky2->tx_le)
+               goto nomem;
+
+       sky2->tx_ring = kcalloc(sky2->tx_ring_size, sizeof(struct tx_ring_info),
+                               GFP_KERNEL);
+       if (!sky2->tx_ring)
+               goto nomem;
+
+       sky2->rx_le = pci_alloc_consistent(hw->pdev, RX_LE_BYTES,
+                                          &sky2->rx_le_map);
+       if (!sky2->rx_le)
+               goto nomem;
+       memset(sky2->rx_le, 0, RX_LE_BYTES);
+
+       sky2->rx_ring = kcalloc(sky2->rx_pending, sizeof(struct rx_ring_info),
+                               GFP_KERNEL);
+       if (!sky2->rx_ring)
+               goto nomem;
+
+       return 0;
+nomem:
+       return -ENOMEM;
+}
+
+static void sky2_free_buffers(struct sky2_port *sky2)
+{
+       struct sky2_hw *hw = sky2->hw;
+
+       if (sky2->rx_le) {
+               pci_free_consistent(hw->pdev, RX_LE_BYTES,
+                                   sky2->rx_le, sky2->rx_le_map);
+               sky2->rx_le = NULL;
+       }
+       if (sky2->tx_le) {
+               pci_free_consistent(hw->pdev,
+                                   sky2->tx_ring_size * sizeof(struct sky2_tx_le),
+                                   sky2->tx_le, sky2->tx_le_map);
+               sky2->tx_le = NULL;
+       }
+       kfree(sky2->tx_ring);
+       kfree(sky2->rx_ring);
+
+       sky2->tx_ring = NULL;
+       sky2->rx_ring = NULL;
+}
+
 /* Bring up network interface. */
 static int sky2_up(struct net_device *dev)
 {
@@ -1412,7 +1465,7 @@ static int sky2_up(struct net_device *dev)
        struct sky2_hw *hw = sky2->hw;
        unsigned port = sky2->port;
        u32 imask, ramsize;
-       int cap, err = -ENOMEM;
+       int cap, err;
        struct net_device *otherdev = hw->dev[sky2->port^1];
 
        /*
@@ -1431,32 +1484,12 @@ static int sky2_up(struct net_device *dev)
 
        netif_carrier_off(dev);
 
-       /* must be power of 2 */
-       sky2->tx_le = pci_alloc_consistent(hw->pdev,
-                                          sky2->tx_ring_size *
-                                          sizeof(struct sky2_tx_le),
-                                          &sky2->tx_le_map);
-       if (!sky2->tx_le)
-               goto err_out;
-
-       sky2->tx_ring = kcalloc(sky2->tx_ring_size, sizeof(struct tx_ring_info),
-                               GFP_KERNEL);
-       if (!sky2->tx_ring)
+       err = sky2_alloc_buffers(sky2);
+       if (err)
                goto err_out;
 
        tx_init(sky2);
 
-       sky2->rx_le = pci_alloc_consistent(hw->pdev, RX_LE_BYTES,
-                                          &sky2->rx_le_map);
-       if (!sky2->rx_le)
-               goto err_out;
-       memset(sky2->rx_le, 0, RX_LE_BYTES);
-
-       sky2->rx_ring = kcalloc(sky2->rx_pending, sizeof(struct rx_ring_info),
-                               GFP_KERNEL);
-       if (!sky2->rx_ring)
-               goto err_out;
-
        sky2_mac_init(hw, port);
 
        /* Register is number of 4K blocks on internal RAM buffer. */
@@ -1513,22 +1546,7 @@ static int sky2_up(struct net_device *dev)
        return 0;
 
 err_out:
-       if (sky2->rx_le) {
-               pci_free_consistent(hw->pdev, RX_LE_BYTES,
-                                   sky2->rx_le, sky2->rx_le_map);
-               sky2->rx_le = NULL;
-       }
-       if (sky2->tx_le) {
-               pci_free_consistent(hw->pdev,
-                                   sky2->tx_ring_size * sizeof(struct sky2_tx_le),
-                                   sky2->tx_le, sky2->tx_le_map);
-               sky2->tx_le = NULL;
-       }
-       kfree(sky2->tx_ring);
-       kfree(sky2->rx_ring);
-
-       sky2->tx_ring = NULL;
-       sky2->rx_ring = NULL;
+       sky2_free_buffers(sky2);
        return err;
 }
 
@@ -1549,11 +1567,13 @@ static unsigned tx_le_req(const struct sk_buff *skb)
 {
        unsigned count;
 
-       count = sizeof(dma_addr_t) / sizeof(u32);
-       count += skb_shinfo(skb)->nr_frags * count;
+       count = (skb_shinfo(skb)->nr_frags + 1)
+               * (sizeof(dma_addr_t) / sizeof(u32));
 
        if (skb_is_gso(skb))
                ++count;
+       else if (sizeof(dma_addr_t) == sizeof(u32))
+               ++count;        /* possible vlan */
 
        if (skb->ip_summed == CHECKSUM_PARTIAL)
                ++count;
@@ -1880,20 +1900,7 @@ static int sky2_down(struct net_device *dev)
 
        sky2_rx_clean(sky2);
 
-       pci_free_consistent(hw->pdev, RX_LE_BYTES,
-                           sky2->rx_le, sky2->rx_le_map);
-       kfree(sky2->rx_ring);
-
-       pci_free_consistent(hw->pdev,
-                           sky2->tx_ring_size * sizeof(struct sky2_tx_le),
-                           sky2->tx_le, sky2->tx_le_map);
-       kfree(sky2->tx_ring);
-
-       sky2->tx_le = NULL;
-       sky2->rx_le = NULL;
-
-       sky2->rx_ring = NULL;
-       sky2->tx_ring = NULL;
+       sky2_free_buffers(sky2);
 
        return 0;
 }
@@ -4543,16 +4550,18 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
        if (hw->ports > 1) {
                struct net_device *dev1;
 
+               err = -ENOMEM;
                dev1 = sky2_init_netdev(hw, 1, using_dac, wol_default);
-               if (!dev1)
-                       dev_warn(&pdev->dev, "allocation for second device failed\n");
-               else if ((err = register_netdev(dev1))) {
+               if (dev1 && (err = register_netdev(dev1)) == 0)
+                       sky2_show_addr(dev1);
+               else {
                        dev_warn(&pdev->dev,
                                 "register of second port failed (%d)\n", err);
                        hw->dev[1] = NULL;
-                       free_netdev(dev1);
-               } else
-                       sky2_show_addr(dev1);
+                       hw->ports = 1;
+                       if (dev1)
+                               free_netdev(dev1);
+               }
        }
 
        setup_timer(&hw->watchdog_timer, sky2_watchdog, (unsigned long) hw);