]> err.no Git - linux-2.6/blobdiff - drivers/net/netxen/netxen_nic_main.c
x86: work around MTRR mask setting, v2
[linux-2.6] / drivers / net / netxen / netxen_nic_main.c
index 4d32f3cc2fbd8a5e17e827d6f64590f3d369210c..7615c715e66efd0b3cffb33d1c103f79c1c50916 100644 (file)
@@ -58,10 +58,6 @@ static int use_msi = 1;
 
 static int use_msi_x = 1;
 
-#define NETXEN_NETDEV_WEIGHT 120
-#define NETXEN_ADAPTER_UP_MAGIC 777
-#define NETXEN_NIC_PEG_TUNE 0
-
 /* Local functions to NetXen NIC driver */
 static int __devinit netxen_nic_probe(struct pci_dev *pdev,
                const struct pci_device_id *ent);
@@ -123,7 +119,7 @@ static uint32_t crb_cmd_producer[4] = {
        CRB_CMD_PRODUCER_OFFSET_2, CRB_CMD_PRODUCER_OFFSET_3
 };
 
-static inline void
+void
 netxen_nic_update_cmd_producer(struct netxen_adapter *adapter,
                uint32_t crb_producer)
 {
@@ -151,22 +147,17 @@ static uint32_t msi_tgt_status[8] = {
        ISR_INT_TARGET_STATUS_F6, ISR_INT_TARGET_STATUS_F7
 };
 
-static uint32_t sw_int_mask[4] = {
-       CRB_SW_INT_MASK_0, CRB_SW_INT_MASK_1,
-       CRB_SW_INT_MASK_2, CRB_SW_INT_MASK_3
-};
-
 static struct netxen_legacy_intr_set legacy_intr[] = NX_LEGACY_INTR_CONFIG;
 
 static void netxen_nic_disable_int(struct netxen_adapter *adapter)
 {
        u32 mask = 0x7ff;
        int retries = 32;
-       int port = adapter->portnum;
        int pci_fn = adapter->ahw.pci_func;
 
        if (adapter->msi_mode != MSI_MODE_MULTIFUNC)
-               adapter->pci_write_normalize(adapter, sw_int_mask[port], 0);
+               adapter->pci_write_normalize(adapter,
+                               adapter->crb_intr_mask, 0);
 
        if (adapter->intr_scheme != -1 &&
            adapter->intr_scheme != INTR_SCHEME_PERPORT)
@@ -175,7 +166,8 @@ static void netxen_nic_disable_int(struct netxen_adapter *adapter)
        if (!NETXEN_IS_MSI_FAMILY(adapter)) {
                do {
                        adapter->pci_write_immediate(adapter,
-                                       ISR_INT_TARGET_STATUS, 0xffffffff);
+                                       adapter->legacy_intr.tgt_status_reg,
+                                       0xffffffff);
                        mask = adapter->pci_read_immediate(adapter,
                                        ISR_INT_VECTOR);
                        if (!(mask & 0x80))
@@ -184,7 +176,7 @@ static void netxen_nic_disable_int(struct netxen_adapter *adapter)
                } while (--retries);
 
                if (!retries) {
-                       printk(KERN_NOTICE "%s: Failed to disable interrupt completely\n",
+                       printk(KERN_NOTICE "%s: Failed to disable interrupt\n",
                                        netxen_nic_driver_name);
                }
        } else {
@@ -198,9 +190,6 @@ static void netxen_nic_disable_int(struct netxen_adapter *adapter)
 static void netxen_nic_enable_int(struct netxen_adapter *adapter)
 {
        u32 mask;
-       int port = adapter->portnum;
-
-       DPRINTK(1, INFO, "Entered ISR Enable \n");
 
        if (adapter->intr_scheme != -1 &&
                adapter->intr_scheme != INTR_SCHEME_PERPORT) {
@@ -219,20 +208,17 @@ static void netxen_nic_enable_int(struct netxen_adapter *adapter)
                adapter->pci_write_immediate(adapter, ISR_INT_MASK, mask);
        }
 
-       adapter->pci_write_normalize(adapter, sw_int_mask[port], 0x1);
+       adapter->pci_write_normalize(adapter, adapter->crb_intr_mask, 0x1);
 
        if (!NETXEN_IS_MSI_FAMILY(adapter)) {
                mask = 0xbff;
-               if (adapter->intr_scheme != -1 &&
-                       adapter->intr_scheme != INTR_SCHEME_PERPORT) {
+               if (adapter->intr_scheme == INTR_SCHEME_PERPORT)
+                       adapter->pci_write_immediate(adapter,
+                               adapter->legacy_intr.tgt_mask_reg, mask);
+               else
                        adapter->pci_write_normalize(adapter,
                                        CRB_INT_VECTOR, 0);
-               }
-               adapter->pci_write_immediate(adapter,
-                               ISR_INT_TARGET_MASK, mask);
        }
-
-       DPRINTK(1, INFO, "Done with enable Int\n");
 }
 
 static int nx_set_dma_mask(struct netxen_adapter *adapter, uint8_t revision_id)
@@ -294,6 +280,8 @@ static void netxen_check_options(struct netxen_adapter *adapter)
        case NETXEN_BRDTYPE_P3_10G_CX4_LP:
        case NETXEN_BRDTYPE_P3_IMEZ:
        case NETXEN_BRDTYPE_P3_10G_SFP_PLUS:
+       case NETXEN_BRDTYPE_P3_10G_SFP_QT:
+       case NETXEN_BRDTYPE_P3_10G_SFP_CT:
        case NETXEN_BRDTYPE_P3_10G_XFP:
        case NETXEN_BRDTYPE_P3_10000_BASE_T:
                adapter->msix_supported = !!use_msi_x;
@@ -311,6 +299,10 @@ static void netxen_check_options(struct netxen_adapter *adapter)
        case NETXEN_BRDTYPE_P3_REF_QG:
        case NETXEN_BRDTYPE_P3_4_GB:
        case NETXEN_BRDTYPE_P3_4_GB_MM:
+               adapter->msix_supported = 0;
+               adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_10G;
+               break;
+
        case NETXEN_BRDTYPE_P2_SB35_4G:
        case NETXEN_BRDTYPE_P2_SB31_2G:
                adapter->msix_supported = 0;
@@ -719,7 +711,10 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        netdev->stop               = netxen_nic_close;
        netdev->hard_start_xmit    = netxen_nic_xmit_frame;
        netdev->get_stats          = netxen_nic_get_stats;
-       netdev->set_multicast_list = netxen_nic_set_multi;
+       if (NX_IS_REVISION_P3(revision_id))
+               netdev->set_multicast_list = netxen_p3_nic_set_multi;
+       else
+               netdev->set_multicast_list = netxen_p2_nic_set_multi;
        netdev->set_mac_address    = netxen_nic_set_mac;
        netdev->change_mtu         = netxen_nic_change_mtu;
        netdev->tx_timeout         = netxen_tx_timeout;
@@ -735,8 +730,10 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        netdev->features = NETIF_F_SG;
        netdev->features |= NETIF_F_IP_CSUM;
        netdev->features |= NETIF_F_TSO;
-       if (NX_IS_REVISION_P3(revision_id))
+       if (NX_IS_REVISION_P3(revision_id)) {
+               netdev->features |= NETIF_F_IPV6_CSUM;
                netdev->features |= NETIF_F_TSO6;
+       }
 
        if (adapter->pci_using_dac)
                netdev->features |= NETIF_F_HIGHDMA;
@@ -781,10 +778,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                if (adapter->portnum == 0)
                        first_driver = 1;
        }
-       adapter->crb_addr_cmd_producer = crb_cmd_producer[adapter->portnum];
-       adapter->crb_addr_cmd_consumer = crb_cmd_consumer[adapter->portnum];
-       netxen_nic_update_cmd_producer(adapter, 0);
-       netxen_nic_update_cmd_consumer(adapter, 0);
 
        if (first_driver) {
                first_boot = adapter->pci_read_normalize(adapter,
@@ -844,17 +837,18 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                /* Handshake with the card before we register the devices. */
                netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
 
-               if (NX_IS_REVISION_P3(revision_id)) {
-                       adapter->hw_read_wx(adapter,
-                                       NETXEN_MIU_MN_CONTROL, &val, 4);
-                       adapter->ahw.cut_through = (val & 0x4) ? 1 : 0;
-                       dev_info(&pdev->dev, "firmware running in %s mode\n",
-                       adapter->ahw.cut_through ? "cut through" : "legacy");
-               }
        }       /* first_driver */
 
        netxen_nic_flash_print(adapter);
 
+       if (NX_IS_REVISION_P3(revision_id)) {
+               adapter->hw_read_wx(adapter,
+                               NETXEN_MIU_MN_CONTROL, &val, 4);
+               adapter->ahw.cut_through = (val & 0x4) ? 1 : 0;
+               dev_info(&pdev->dev, "firmware running in %s mode\n",
+               adapter->ahw.cut_through ? "cut through" : "legacy");
+       }
+
        /*
         * See if the firmware gave us a virtual-physical port mapping.
         */
@@ -904,7 +898,7 @@ request_msi:
                goto err_out_disable_msi;
 
        init_timer(&adapter->watchdog_timer);
-       adapter->ahw.xg_linkup = 0;
+       adapter->ahw.linkup = 0;
        adapter->watchdog_timer.function = &netxen_watchdog;
        adapter->watchdog_timer.data = (unsigned long)adapter;
        INIT_WORK(&adapter->watchdog_task, netxen_watchdog_task);
@@ -1054,6 +1048,11 @@ static int netxen_nic_open(struct net_device *netdev)
                        return -EIO;
                }
 
+               if (adapter->fw_major < 4)
+                       adapter->max_rds_rings = 3;
+               else
+                       adapter->max_rds_rings = 2;
+
                err = netxen_alloc_sw_resources(adapter);
                if (err) {
                        printk(KERN_ERR "%s: Error in setting sw resources\n",
@@ -1075,13 +1074,13 @@ static int netxen_nic_open(struct net_device *netdev)
                                crb_cmd_producer[adapter->portnum];
                        adapter->crb_addr_cmd_consumer =
                                crb_cmd_consumer[adapter->portnum];
-               }
 
-               netxen_nic_update_cmd_producer(adapter, 0);
-               netxen_nic_update_cmd_consumer(adapter, 0);
+                       netxen_nic_update_cmd_producer(adapter, 0);
+                       netxen_nic_update_cmd_consumer(adapter, 0);
+               }
 
                for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
-                       for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++)
+                       for (ring = 0; ring < adapter->max_rds_rings; ring++)
                                netxen_post_rx_buffers(adapter, ctx, ring);
                }
                if (NETXEN_IS_MSI_FAMILY(adapter))
@@ -1103,7 +1102,7 @@ static int netxen_nic_open(struct net_device *netdev)
 
        /* Done here again so that even if phantom sw overwrote it,
         * we set it */
-       err = adapter->init_port(adapter, adapter->portnum);
+       err = adapter->init_port(adapter, adapter->physical_port);
        if (err) {
                printk(KERN_ERR "%s: Failed to initialize port %d\n",
                                netxen_nic_driver_name, adapter->portnum);
@@ -1113,8 +1112,9 @@ static int netxen_nic_open(struct net_device *netdev)
 
        netxen_nic_set_link_parameters(adapter);
 
-       netxen_nic_set_multi(netdev);
-       adapter->set_mtu(adapter, netdev->mtu);
+       netdev->set_multicast_list(netdev);
+       if (adapter->set_mtu)
+               adapter->set_mtu(adapter, netdev->mtu);
 
        mod_timer(&adapter->watchdog_timer, jiffies);
 
@@ -1160,6 +1160,31 @@ static int netxen_nic_close(struct net_device *netdev)
        return 0;
 }
 
+void netxen_tso_check(struct netxen_adapter *adapter,
+                     struct cmd_desc_type0 *desc, struct sk_buff *skb)
+{
+       if (desc->mss) {
+               desc->total_hdr_length = (sizeof(struct ethhdr) +
+                                         ip_hdrlen(skb) + tcp_hdrlen(skb));
+
+               if ((NX_IS_REVISION_P3(adapter->ahw.revision_id)) &&
+                               (skb->protocol == htons(ETH_P_IPV6)))
+                       netxen_set_cmd_desc_opcode(desc, TX_TCP_LSO6);
+               else
+                       netxen_set_cmd_desc_opcode(desc, TX_TCP_LSO);
+
+       } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
+               if (ip_hdr(skb)->protocol == IPPROTO_TCP)
+                       netxen_set_cmd_desc_opcode(desc, TX_TCP_PKT);
+               else if (ip_hdr(skb)->protocol == IPPROTO_UDP)
+                       netxen_set_cmd_desc_opcode(desc, TX_UDP_PKT);
+               else
+                       return;
+       }
+       desc->tcp_hdr_offset = skb_transport_offset(skb);
+       desc->ip_hdr_offset = skb_network_offset(skb);
+}
+
 static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 {
        struct netxen_adapter *adapter = netdev_priv(netdev);
@@ -1181,7 +1206,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 
        /* There 4 fragments per descriptor */
        no_of_desc = (frag_count + 3) >> 2;
-       if (netdev->features & NETIF_F_TSO) {
+       if (netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) {
                if (skb_shinfo(skb)->gso_size > 0) {
 
                        no_of_desc++;
@@ -1208,7 +1233,8 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        memset(hwdesc, 0, sizeof(struct cmd_desc_type0));
        /* Take skb->data itself */
        pbuf = &adapter->cmd_buf_arr[producer];
-       if ((netdev->features & NETIF_F_TSO) && skb_shinfo(skb)->gso_size > 0) {
+       if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) &&
+                       skb_shinfo(skb)->gso_size > 0) {
                pbuf->mss = skb_shinfo(skb)->gso_size;
                hwdesc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
        } else {
@@ -1335,6 +1361,86 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        return NETDEV_TX_OK;
 }
 
+static int netxen_nic_check_temp(struct netxen_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+       uint32_t temp, temp_state, temp_val;
+       int rv = 0;
+
+       temp = adapter->pci_read_normalize(adapter, CRB_TEMP_STATE);
+
+       temp_state = nx_get_temp_state(temp);
+       temp_val = nx_get_temp_val(temp);
+
+       if (temp_state == NX_TEMP_PANIC) {
+               printk(KERN_ALERT
+                      "%s: Device temperature %d degrees C exceeds"
+                      " maximum allowed. Hardware has been shut down.\n",
+                      netxen_nic_driver_name, temp_val);
+
+               netif_carrier_off(netdev);
+               netif_stop_queue(netdev);
+               rv = 1;
+       } else if (temp_state == NX_TEMP_WARN) {
+               if (adapter->temp == NX_TEMP_NORMAL) {
+                       printk(KERN_ALERT
+                              "%s: Device temperature %d degrees C "
+                              "exceeds operating range."
+                              " Immediate action needed.\n",
+                              netxen_nic_driver_name, temp_val);
+               }
+       } else {
+               if (adapter->temp == NX_TEMP_WARN) {
+                       printk(KERN_INFO
+                              "%s: Device temperature is now %d degrees C"
+                              " in normal range.\n", netxen_nic_driver_name,
+                              temp_val);
+               }
+       }
+       adapter->temp = temp_state;
+       return rv;
+}
+
+static void netxen_nic_handle_phy_intr(struct netxen_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+       u32 val, port, linkup;
+
+       port = adapter->physical_port;
+
+       if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
+               val = adapter->pci_read_normalize(adapter, CRB_XG_STATE_P3);
+               val = XG_LINK_STATE_P3(adapter->ahw.pci_func, val);
+               linkup = (val == XG_LINK_UP_P3);
+       } else {
+               val = adapter->pci_read_normalize(adapter, CRB_XG_STATE);
+               if (adapter->ahw.board_type == NETXEN_NIC_GBE)
+                       linkup = (val >> port) & 1;
+               else {
+                       val = (val >> port*8) & 0xff;
+                       linkup = (val == XG_LINK_UP);
+               }
+       }
+
+       if (adapter->ahw.linkup && !linkup) {
+               printk(KERN_INFO "%s: %s NIC Link is down\n",
+                      netxen_nic_driver_name, netdev->name);
+               adapter->ahw.linkup = 0;
+               if (netif_running(netdev)) {
+                       netif_carrier_off(netdev);
+                       netif_stop_queue(netdev);
+               }
+       } else if (!adapter->ahw.linkup && linkup) {
+               printk(KERN_INFO "%s: %s NIC Link is up\n",
+                      netxen_nic_driver_name, netdev->name);
+               adapter->ahw.linkup = 1;
+               if (netif_running(netdev)) {
+                       netif_carrier_on(netdev);
+                       netif_wake_queue(netdev);
+               }
+       }
+}
+
 static void netxen_watchdog(unsigned long v)
 {
        struct netxen_adapter *adapter = (struct netxen_adapter *)v;
@@ -1342,6 +1448,19 @@ static void netxen_watchdog(unsigned long v)
        SCHEDULE_WORK(&adapter->watchdog_task);
 }
 
+void netxen_watchdog_task(struct work_struct *work)
+{
+       struct netxen_adapter *adapter =
+               container_of(work, struct netxen_adapter, watchdog_task);
+
+       if ((adapter->portnum  == 0) && netxen_nic_check_temp(adapter))
+               return;
+
+       netxen_nic_handle_phy_intr(adapter);
+
+       mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
+}
+
 static void netxen_tx_timeout(struct net_device *netdev)
 {
        struct netxen_adapter *adapter = (struct netxen_adapter *)
@@ -1367,6 +1486,38 @@ static void netxen_tx_timeout_task(struct work_struct *work)
        netif_wake_queue(adapter->netdev);
 }
 
+/*
+ * netxen_nic_get_stats - Get System Network Statistics
+ * @netdev: network interface device structure
+ */
+struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev)
+{
+       struct netxen_adapter *adapter = netdev_priv(netdev);
+       struct net_device_stats *stats = &adapter->net_stats;
+
+       memset(stats, 0, sizeof(*stats));
+
+       /* total packets received   */
+       stats->rx_packets = adapter->stats.no_rcv;
+       /* total packets transmitted    */
+       stats->tx_packets = adapter->stats.xmitedframes +
+               adapter->stats.xmitfinished;
+       /* total bytes received     */
+       stats->rx_bytes = adapter->stats.rxbytes;
+       /* total bytes transmitted  */
+       stats->tx_bytes = adapter->stats.txbytes;
+       /* bad packets received     */
+       stats->rx_errors = adapter->stats.rcvdbadskb;
+       /* packet transmit problems */
+       stats->tx_errors = adapter->stats.nocmddescriptor;
+       /* no space in linux buffers    */
+       stats->rx_dropped = adapter->stats.rxdropped;
+       /* no space available in linux  */
+       stats->tx_dropped = adapter->stats.txdropped;
+
+       return stats;
+}
+
 static inline void
 netxen_handle_int(struct netxen_adapter *adapter)
 {
@@ -1379,15 +1530,33 @@ static irqreturn_t netxen_intr(int irq, void *data)
        struct netxen_adapter *adapter = data;
        u32 our_int = 0;
 
-       our_int = adapter->pci_read_normalize(adapter, CRB_INT_VECTOR);
-       /* not our interrupt */
-       if ((our_int & (0x80 << adapter->portnum)) == 0)
+       u32 status = 0;
+
+       status = adapter->pci_read_immediate(adapter, ISR_INT_VECTOR);
+
+       if (!(status & adapter->legacy_intr.int_vec_bit))
                return IRQ_NONE;
 
-       if (adapter->intr_scheme == INTR_SCHEME_PERPORT) {
-               /* claim interrupt */
-               adapter->pci_write_normalize(adapter, CRB_INT_VECTOR,
+       if (adapter->ahw.revision_id >= NX_P3_B1) {
+               /* check interrupt state machine, to be sure */
+               status = adapter->pci_read_immediate(adapter,
+                               ISR_INT_STATE_REG);
+               if (!ISR_LEGACY_INT_TRIGGERED(status))
+                       return IRQ_NONE;
+
+       } else if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
+
+               our_int = adapter->pci_read_normalize(adapter, CRB_INT_VECTOR);
+               /* not our interrupt */
+               if ((our_int & (0x80 << adapter->portnum)) == 0)
+                       return IRQ_NONE;
+
+               if (adapter->intr_scheme == INTR_SCHEME_PERPORT) {
+                       /* claim interrupt */
+                       adapter->pci_write_normalize(adapter,
+                               CRB_INT_VECTOR,
                                our_int & ~((u32)(0x80 << adapter->portnum)));
+               }
        }
 
        netxen_handle_int(adapter);