Merge branch 'master' into upstream
[pandora-kernel.git] / drivers / net / cxgb3 / cxgb3_main.c
index 54c49ac..43583ed 100644 (file)
@@ -1,14 +1,34 @@
 /*
- * This file is part of the Chelsio T3 Ethernet driver for Linux.
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
  *
- * Copyright (C) 2003-2006 Chelsio Communications.  All rights reserved.
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
  *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the LICENSE file included in this
- * release for licensing terms and conditions.
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
  */
-
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
@@ -54,8 +74,6 @@ enum {
 
 #define EEPROM_MAGIC 0x38E2F10C
 
-#define to_net_dev(class) container_of(class, struct net_device, class_dev)
-
 #define CH_DEVICE(devid, ssid, idx) \
        { PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, ssid, 0, 0, idx }
 
@@ -75,7 +93,7 @@ static const struct pci_device_id cxgb3_pci_tbl[] = {
 
 MODULE_DESCRIPTION(DRV_DESC);
 MODULE_AUTHOR("Chelsio Communications");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("Dual BSD/GPL");
 MODULE_VERSION(DRV_VERSION);
 MODULE_DEVICE_TABLE(pci, cxgb3_pci_tbl);
 
@@ -414,11 +432,12 @@ static int setup_sge_qsets(struct adapter *adap)
        return 0;
 }
 
-static ssize_t attr_show(struct class_device *cd, char *buf,
+static ssize_t attr_show(struct device *d, struct device_attribute *attr,
+                        char *buf,
                         ssize_t(*format) (struct adapter *, char *))
 {
        ssize_t len;
-       struct adapter *adap = to_net_dev(cd)->priv;
+       struct adapter *adap = to_net_dev(d)->priv;
 
        /* Synchronize with ioctls that may shut down the device */
        rtnl_lock();
@@ -427,14 +446,15 @@ static ssize_t attr_show(struct class_device *cd, char *buf,
        return len;
 }
 
-static ssize_t attr_store(struct class_device *cd, const char *buf, size_t len,
+static ssize_t attr_store(struct device *d, struct device_attribute *attr,
+                         const char *buf, size_t len,
                          ssize_t(*set) (struct adapter *, unsigned int),
                          unsigned int min_val, unsigned int max_val)
 {
        char *endp;
        ssize_t ret;
        unsigned int val;
-       struct adapter *adap = to_net_dev(cd)->priv;
+       struct adapter *adap = to_net_dev(d)->priv;
 
        if (!capable(CAP_NET_ADMIN))
                return -EPERM;
@@ -456,9 +476,10 @@ static ssize_t format_##name(struct adapter *adap, char *buf) \
 { \
        return sprintf(buf, "%u\n", val_expr); \
 } \
-static ssize_t show_##name(struct class_device *cd, char *buf) \
+static ssize_t show_##name(struct device *d, struct device_attribute *attr, \
+                          char *buf) \
 { \
-       return attr_show(cd, buf, format_##name); \
+       return attr_show(d, attr, buf, format_##name); \
 }
 
 static ssize_t set_nfilters(struct adapter *adap, unsigned int val)
@@ -473,10 +494,10 @@ static ssize_t set_nfilters(struct adapter *adap, unsigned int val)
        return 0;
 }
 
-static ssize_t store_nfilters(struct class_device *cd, const char *buf,
-                             size_t len)
+static ssize_t store_nfilters(struct device *d, struct device_attribute *attr,
+                             const char *buf, size_t len)
 {
-       return attr_store(cd, buf, len, set_nfilters, 0, ~0);
+       return attr_store(d, attr, buf, len, set_nfilters, 0, ~0);
 }
 
 static ssize_t set_nservers(struct adapter *adap, unsigned int val)
@@ -489,38 +510,39 @@ static ssize_t set_nservers(struct adapter *adap, unsigned int val)
        return 0;
 }
 
-static ssize_t store_nservers(struct class_device *cd, const char *buf,
-                             size_t len)
+static ssize_t store_nservers(struct device *d, struct device_attribute *attr,
+                             const char *buf, size_t len)
 {
-       return attr_store(cd, buf, len, set_nservers, 0, ~0);
+       return attr_store(d, attr, buf, len, set_nservers, 0, ~0);
 }
 
 #define CXGB3_ATTR_R(name, val_expr) \
 CXGB3_SHOW(name, val_expr) \
-static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
+static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
 
 #define CXGB3_ATTR_RW(name, val_expr, store_method) \
 CXGB3_SHOW(name, val_expr) \
-static CLASS_DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_method)
+static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_method)
 
 CXGB3_ATTR_R(cam_size, t3_mc5_size(&adap->mc5));
 CXGB3_ATTR_RW(nfilters, adap->params.mc5.nfilters, store_nfilters);
 CXGB3_ATTR_RW(nservers, adap->params.mc5.nservers, store_nservers);
 
 static struct attribute *cxgb3_attrs[] = {
-       &class_device_attr_cam_size.attr,
-       &class_device_attr_nfilters.attr,
-       &class_device_attr_nservers.attr,
+       &dev_attr_cam_size.attr,
+       &dev_attr_nfilters.attr,
+       &dev_attr_nservers.attr,
        NULL
 };
 
 static struct attribute_group cxgb3_attr_group = {.attrs = cxgb3_attrs };
 
-static ssize_t tm_attr_show(struct class_device *cd, char *buf, int sched)
+static ssize_t tm_attr_show(struct device *d, struct device_attribute *attr,
+                           char *buf, int sched)
 {
        ssize_t len;
        unsigned int v, addr, bpt, cpt;
-       struct adapter *adap = to_net_dev(cd)->priv;
+       struct adapter *adap = to_net_dev(d)->priv;
 
        addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2;
        rtnl_lock();
@@ -540,13 +562,13 @@ static ssize_t tm_attr_show(struct class_device *cd, char *buf, int sched)
        return len;
 }
 
-static ssize_t tm_attr_store(struct class_device *cd, const char *buf,
-                            size_t len, int sched)
+static ssize_t tm_attr_store(struct device *d, struct device_attribute *attr,
+                            const char *buf, size_t len, int sched)
 {
        char *endp;
        ssize_t ret;
        unsigned int val;
-       struct adapter *adap = to_net_dev(cd)->priv;
+       struct adapter *adap = to_net_dev(d)->priv;
 
        if (!capable(CAP_NET_ADMIN))
                return -EPERM;
@@ -564,15 +586,17 @@ static ssize_t tm_attr_store(struct class_device *cd, const char *buf,
 }
 
 #define TM_ATTR(name, sched) \
-static ssize_t show_##name(struct class_device *cd, char *buf) \
+static ssize_t show_##name(struct device *d, struct device_attribute *attr, \
+                          char *buf) \
 { \
-       return tm_attr_show(cd, buf, sched); \
+       return tm_attr_show(d, attr, buf, sched); \
 } \
-static ssize_t store_##name(struct class_device *cd, const char *buf, size_t len) \
+static ssize_t store_##name(struct device *d, struct device_attribute *attr, \
+                           const char *buf, size_t len) \
 { \
-       return tm_attr_store(cd, buf, len, sched); \
+       return tm_attr_store(d, attr, buf, len, sched); \
 } \
-static CLASS_DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_##name)
+static DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_##name)
 
 TM_ATTR(sched0, 0);
 TM_ATTR(sched1, 1);
@@ -584,14 +608,14 @@ TM_ATTR(sched6, 6);
 TM_ATTR(sched7, 7);
 
 static struct attribute *offload_attrs[] = {
-       &class_device_attr_sched0.attr,
-       &class_device_attr_sched1.attr,
-       &class_device_attr_sched2.attr,
-       &class_device_attr_sched3.attr,
-       &class_device_attr_sched4.attr,
-       &class_device_attr_sched5.attr,
-       &class_device_attr_sched6.attr,
-       &class_device_attr_sched7.attr,
+       &dev_attr_sched0.attr,
+       &dev_attr_sched1.attr,
+       &dev_attr_sched2.attr,
+       &dev_attr_sched3.attr,
+       &dev_attr_sched4.attr,
+       &dev_attr_sched5.attr,
+       &dev_attr_sched6.attr,
+       &dev_attr_sched7.attr,
        NULL
 };
 
@@ -649,6 +673,37 @@ static void init_port_mtus(struct adapter *adapter)
        t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus);
 }
 
+static void send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,
+                             int hi, int port)
+{
+       struct sk_buff *skb;
+       struct mngt_pktsched_wr *req;
+
+       skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL);
+       req = (struct mngt_pktsched_wr *)skb_put(skb, sizeof(*req));
+       req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT));
+       req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET;
+       req->sched = sched;
+       req->idx = qidx;
+       req->min = lo;
+       req->max = hi;
+       req->binding = port;
+       t3_mgmt_tx(adap, skb);
+}
+
+static void bind_qsets(struct adapter *adap)
+{
+       int i, j;
+
+       for_each_port(adap, i) {
+               const struct port_info *pi = adap2pinfo(adap, i);
+
+               for (j = 0; j < pi->nqsets; ++j)
+                       send_pktsched_cmd(adap, 1, pi->first_qset + j, -1,
+                                         -1, i);
+       }
+}
+
 /**
  *     cxgb_up - enable the adapter
  *     @adapter: adapter being enabled
@@ -665,11 +720,8 @@ static int cxgb_up(struct adapter *adap)
 
        if (!(adap->flags & FULL_INIT_DONE)) {
                err = t3_check_fw_version(adap);
-               if (err) {
-                       dev_err(&adap->pdev->dev,
-                               "adapter FW is not compatible with driver\n");
+               if (err)
                        goto out;
-               }
 
                err = init_dummy_netdevs(adap);
                if (err)
@@ -705,12 +757,18 @@ static int cxgb_up(struct adapter *adap)
                                      t3_intr_handler(adap,
                                                      adap->sge.qs[0].rspq.
                                                      polling),
-                                     (adap->flags & USING_MSI) ? 0 : SA_SHIRQ,
+                                     (adap->flags & USING_MSI) ?
+                                      0 : IRQF_SHARED,
                                      adap->name, adap)))
                goto irq_err;
 
        t3_sge_start(adap);
        t3_intr_enable(adap);
+
+       if ((adap->flags & (USING_MSIX | QUEUES_BOUND)) == USING_MSIX)
+               bind_qsets(adap);
+       adap->flags |= QUEUES_BOUND;
+
 out:
        return err;
 irq_err:
@@ -783,7 +841,7 @@ static int offload_open(struct net_device *dev)
        init_smt(adapter);
 
        /* Never mind if the next step fails */
-       sysfs_create_group(&tdev->lldev->class_dev.kobj, &offload_attr_group);
+       sysfs_create_group(&tdev->lldev->dev.kobj, &offload_attr_group);
 
        /* Call back all registered clients */
        cxgb3_add_clients(tdev);
@@ -808,7 +866,7 @@ static int offload_close(struct t3cdev *tdev)
        /* Call back all registered clients */
        cxgb3_remove_clients(tdev);
 
-       sysfs_remove_group(&tdev->lldev->class_dev.kobj, &offload_attr_group);
+       sysfs_remove_group(&tdev->lldev->dev.kobj, &offload_attr_group);
 
        tdev->lldev = NULL;
        cxgb3_set_dummy_ops(tdev);
@@ -1002,10 +1060,14 @@ static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
        strcpy(info->bus_info, pci_name(adapter->pdev));
        if (!fw_vers)
                strcpy(info->fw_version, "N/A");
-       else
+       else {
                snprintf(info->fw_version, sizeof(info->fw_version),
-                        "%s %u.%u", (fw_vers >> 24) ? "T" : "N",
-                        (fw_vers >> 12) & 0xfff, fw_vers & 0xfff);
+                        "%s %u.%u.%u",
+                        G_FW_VERSION_TYPE(fw_vers) ? "T" : "N",
+                        G_FW_VERSION_MAJOR(fw_vers),
+                        G_FW_VERSION_MINOR(fw_vers),
+                        G_FW_VERSION_MICRO(fw_vers));
+       }
 }
 
 static void get_strings(struct net_device *dev, u32 stringset, u8 * data)
@@ -1829,34 +1891,18 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
                break;
        }
        case CHELSIO_SET_PKTSCHED:{
-               struct sk_buff *skb;
                struct ch_pktsched_params p;
-               struct mngt_pktsched_wr *req;
 
-               if (!(adapter->flags & FULL_INIT_DONE))
-                       return -EIO;    /* uP must be up and running */
+               if (!capable(CAP_NET_ADMIN))
+                               return -EPERM;
+               if (!adapter->open_device_map)
+                               return -EAGAIN; /* uP and SGE must be running */
                if (copy_from_user(&p, useraddr, sizeof(p)))
-                       return -EFAULT;
-               skb = alloc_skb(sizeof(*req), GFP_KERNEL);
-               if (!skb)
-                       return -ENOMEM;
-               req =
-                       (struct mngt_pktsched_wr *)skb_put(skb,
-                                                       sizeof(*req));
-               req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT));
-               req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET;
-               req->sched = p.sched;
-               req->idx = p.idx;
-               req->min = p.min;
-               req->max = p.max;
-               req->binding = p.binding;
-               printk(KERN_INFO
-                       "pktsched: sched %u idx %u min %u max %u binding %u\n",
-                       req->sched, req->idx, req->min, req->max,
-                       req->binding);
-               skb->priority = 1;
-               offload_tx(&adapter->tdev, skb);
+                               return -EFAULT;
+               send_pktsched_cmd(adapter, p.sched, p.idx, p.min, p.max,
+                                 p.binding);
                break;
+                       
        }
        default:
                return -EOPNOTSUPP;
@@ -2379,7 +2425,7 @@ static int __devinit init_one(struct pci_dev *pdev,
        else if (msi > 0 && pci_enable_msi(pdev) == 0)
                adapter->flags |= USING_MSI;
 
-       err = sysfs_create_group(&adapter->port[0]->class_dev.kobj,
+       err = sysfs_create_group(&adapter->port[0]->dev.kobj,
                                 &cxgb3_attr_group);
 
        print_port_info(adapter, ai);
@@ -2411,7 +2457,7 @@ static void __devexit remove_one(struct pci_dev *pdev)
                struct adapter *adapter = dev->priv;
 
                t3_sge_stop(adapter);
-               sysfs_remove_group(&adapter->port[0]->class_dev.kobj,
+               sysfs_remove_group(&adapter->port[0]->dev.kobj,
                                   &cxgb3_attr_group);
 
                for_each_port(adapter, i)