- patches.apparmor/remove_suid_new_case_in_2.6.22.diff: Merge fix.
[linux-flexiantxendom0-3.2.10.git] / drivers / infiniband / hw / ipath / ipath_init_chip.c
index d4f6b52..7045ba6 100644 (file)
@@ -216,6 +216,20 @@ static int bringup_link(struct ipath_devdata *dd)
        return ret;
 }
 
+static struct ipath_portdata *create_portdata0(struct ipath_devdata *dd)
+{
+       struct ipath_portdata *pd = NULL;
+
+       pd = kzalloc(sizeof(*pd), GFP_KERNEL);
+       if (pd) {
+               pd->port_dd = dd;
+               pd->port_cnt = 1;
+               /* The port 0 pkey table is used by the layer interface. */
+               pd->port_pkeys[0] = IPATH_DEFAULT_P_KEY;
+       }
+       return pd;
+}
+
 static int init_chip_first(struct ipath_devdata *dd,
                           struct ipath_portdata **pdp)
 {
@@ -271,20 +285,16 @@ static int init_chip_first(struct ipath_devdata *dd,
                goto done;
        }
 
-       dd->ipath_pd[0] = kzalloc(sizeof(*pd), GFP_KERNEL);
+       pd = create_portdata0(dd);
 
-       if (!dd->ipath_pd[0]) {
+       if (!pd) {
                ipath_dev_err(dd, "Unable to allocate portdata for port "
                              "0, failing\n");
                ret = -ENOMEM;
                goto done;
        }
-       pd = dd->ipath_pd[0];
-       pd->port_dd = dd;
-       pd->port_port = 0;
-       pd->port_cnt = 1;
-       /* The port 0 pkey table is used by the layer interface. */
-       pd->port_pkeys[0] = IPATH_DEFAULT_P_KEY;
+       dd->ipath_pd[0] = pd;
+
        dd->ipath_rcvtidcnt =
                ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvtidcnt);
        dd->ipath_rcvtidbase =
@@ -590,6 +600,10 @@ static int init_housekeeping(struct ipath_devdata *dd,
                goto done;
        }
 
+
+       /* clear diagctrl register, in case diags were running and crashed */
+       ipath_write_kreg (dd, dd->ipath_kregs->kr_hwdiagctrl, 0);
+
        /* clear the initial reset flag, in case first driver load */
        ipath_write_kreg(dd, dd->ipath_kregs->kr_errorclear,
                         INFINIPATH_E_RESET);
@@ -668,6 +682,7 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
 {
        int ret = 0, i;
        u32 val32, kpiobufs;
+       u32 piobufs, uports;
        u64 val;
        struct ipath_portdata *pd = NULL; /* keep gcc4 happy */
        gfp_t gfp_flags = GFP_USER | __GFP_COMP;
@@ -702,16 +717,17 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
         * the in memory DMA'ed copies of the registers.  This has to
         * be done early, before we calculate lastport, etc.
         */
-       val = dd->ipath_piobcnt2k + dd->ipath_piobcnt4k;
+       piobufs = dd->ipath_piobcnt2k + dd->ipath_piobcnt4k;
        /*
         * calc number of pioavail registers, and save it; we have 2
         * bits per buffer.
         */
-       dd->ipath_pioavregs = ALIGN(val, sizeof(u64) * BITS_PER_BYTE / 2)
+       dd->ipath_pioavregs = ALIGN(piobufs, sizeof(u64) * BITS_PER_BYTE / 2)
                / (sizeof(u64) * BITS_PER_BYTE / 2);
+       uports = dd->ipath_cfgports ? dd->ipath_cfgports - 1 : 0;
        if (ipath_kpiobufs == 0) {
                /* not set by user (this is default) */
-               if ((dd->ipath_piobcnt2k + dd->ipath_piobcnt4k) > 128)
+               if (piobufs >= (uports * IPATH_MIN_USER_PORT_BUFCNT) + 32)
                        kpiobufs = 32;
                else
                        kpiobufs = 16;
@@ -719,31 +735,25 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
        else
                kpiobufs = ipath_kpiobufs;
 
-       if (kpiobufs >
-           (dd->ipath_piobcnt2k + dd->ipath_piobcnt4k -
-            (dd->ipath_cfgports * IPATH_MIN_USER_PORT_BUFCNT))) {
-               i = dd->ipath_piobcnt2k + dd->ipath_piobcnt4k -
-                       (dd->ipath_cfgports * IPATH_MIN_USER_PORT_BUFCNT);
+       if (kpiobufs + (uports * IPATH_MIN_USER_PORT_BUFCNT) > piobufs) {
+               i = (int) piobufs -
+                       (int) (uports * IPATH_MIN_USER_PORT_BUFCNT);
                if (i < 0)
                        i = 0;
-               dev_info(&dd->pcidev->dev, "Allocating %d PIO bufs for "
-                        "kernel leaves too few for %d user ports "
+               dev_info(&dd->pcidev->dev, "Allocating %d PIO bufs of "
+                        "%d for kernel leaves too few for %d user ports "
                         "(%d each); using %u\n", kpiobufs,
-                        dd->ipath_cfgports - 1,
-                        IPATH_MIN_USER_PORT_BUFCNT, i);
+                        piobufs, uports, IPATH_MIN_USER_PORT_BUFCNT, i);
                /*
                 * shouldn't change ipath_kpiobufs, because could be
                 * different for different devices...
                 */
                kpiobufs = i;
        }
-       dd->ipath_lastport_piobuf =
-               dd->ipath_piobcnt2k + dd->ipath_piobcnt4k - kpiobufs;
-       dd->ipath_pbufsport = dd->ipath_cfgports > 1
-               ? dd->ipath_lastport_piobuf / (dd->ipath_cfgports - 1)
-               : 0;
-       val32 = dd->ipath_lastport_piobuf -
-               (dd->ipath_pbufsport * (dd->ipath_cfgports - 1));
+       dd->ipath_lastport_piobuf = piobufs - kpiobufs;
+       dd->ipath_pbufsport =
+               uports ? dd->ipath_lastport_piobuf / uports : 0;
+       val32 = dd->ipath_lastport_piobuf - (dd->ipath_pbufsport * uports);
        if (val32 > 0) {
                ipath_dbg("allocating %u pbufs/port leaves %u unused, "
                          "add to kernel\n", dd->ipath_pbufsport, val32);
@@ -754,8 +764,7 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
        dd->ipath_lastpioindex = dd->ipath_lastport_piobuf;
        ipath_cdbg(VERBOSE, "%d PIO bufs for kernel out of %d total %u "
                   "each for %u user ports\n", kpiobufs,
-                  dd->ipath_piobcnt2k + dd->ipath_piobcnt4k,
-                  dd->ipath_pbufsport, dd->ipath_cfgports - 1);
+                  piobufs, dd->ipath_pbufsport, uports);
 
        dd->ipath_f_early_init(dd);
 
@@ -839,11 +848,24 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
         * Set up the port 0 (kernel) rcvhdr q and egr TIDs.  If doing
         * re-init, the simplest way to handle this is to free
         * existing, and re-allocate.
+        * Need to re-create rest of port 0 portdata as well.
         */
        if (reinit) {
-               struct ipath_portdata *pd = dd->ipath_pd[0];
-               dd->ipath_pd[0] = NULL;
-               ipath_free_pddata(dd, pd);
+               /* Alloc and init new ipath_portdata for port0,
+                * Then free old pd. Could lead to fragmentation, but also
+                * makes later support for hot-swap easier.
+                */
+               struct ipath_portdata *npd;
+               npd = create_portdata0(dd);
+               if (npd) {
+                       ipath_free_pddata(dd, pd);
+                       dd->ipath_pd[0] = pd = npd;
+               } else {
+                       ipath_dev_err(dd, "Unable to allocate portdata for"
+                                     "  port 0, failing\n");
+                       ret = -ENOMEM;
+                       goto done;
+               }
        }
        dd->ipath_f_tidtemplate(dd);
        ret = ipath_create_rcvhdrq(dd, pd);