Commit 27b044a8 authored by Michael Albaugh's avatar Michael Albaugh Committed by Roland Dreier

IB/ipath: Fix driver crash (in interrupt or during unload) after chip reset

Re-init of the kernel structures after a chip reset was leaving the
portdata structure for port zero in an inconsistent state, and a
pointer to it either stale (in re-init code) or NULL (in devdata)
Fixing the order of operations on this struct, and the condition for
interrupt access, prevents the crashes.
Signed-off-by: default avatarBryan O'Sullivan <bryan.osullivan@qlogic.com>
Signed-off-by: default avatarRoland Dreier <rolandd@cisco.com>
parent 9783ab40
...@@ -216,6 +216,20 @@ static int bringup_link(struct ipath_devdata *dd) ...@@ -216,6 +216,20 @@ static int bringup_link(struct ipath_devdata *dd)
return ret; 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, static int init_chip_first(struct ipath_devdata *dd,
struct ipath_portdata **pdp) struct ipath_portdata **pdp)
{ {
...@@ -271,20 +285,16 @@ static int init_chip_first(struct ipath_devdata *dd, ...@@ -271,20 +285,16 @@ static int init_chip_first(struct ipath_devdata *dd,
goto done; 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 " ipath_dev_err(dd, "Unable to allocate portdata for port "
"0, failing\n"); "0, failing\n");
ret = -ENOMEM; ret = -ENOMEM;
goto done; goto done;
} }
pd = dd->ipath_pd[0]; dd->ipath_pd[0] = pd;
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_rcvtidcnt = dd->ipath_rcvtidcnt =
ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvtidcnt); ipath_read_kreg32(dd, dd->ipath_kregs->kr_rcvtidcnt);
dd->ipath_rcvtidbase = dd->ipath_rcvtidbase =
...@@ -838,11 +848,24 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit) ...@@ -838,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 * Set up the port 0 (kernel) rcvhdr q and egr TIDs. If doing
* re-init, the simplest way to handle this is to free * re-init, the simplest way to handle this is to free
* existing, and re-allocate. * existing, and re-allocate.
* Need to re-create rest of port 0 portdata as well.
*/ */
if (reinit) { if (reinit) {
struct ipath_portdata *pd = dd->ipath_pd[0]; /* Alloc and init new ipath_portdata for port0,
dd->ipath_pd[0] = NULL; * 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); 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); dd->ipath_f_tidtemplate(dd);
ret = ipath_create_rcvhdrq(dd, pd); ret = ipath_create_rcvhdrq(dd, pd);
......
...@@ -207,7 +207,7 @@ void ipath_get_faststats(unsigned long opaque) ...@@ -207,7 +207,7 @@ void ipath_get_faststats(unsigned long opaque)
* don't access the chip while running diags, or memory diags can * don't access the chip while running diags, or memory diags can
* fail * fail
*/ */
if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_PRESENT) || if (!dd->ipath_kregbase || !(dd->ipath_flags & IPATH_INITTED) ||
ipath_diag_inuse) ipath_diag_inuse)
/* but re-arm the timer, for diags case; won't hurt other */ /* but re-arm the timer, for diags case; won't hurt other */
goto done; goto done;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment