Commit f37bda92 authored by Bryan O'Sullivan's avatar Bryan O'Sullivan Committed by Linus Torvalds

[PATCH] IB/ipath: memory management cleanups

Made in-memory rcvhdrq tail update be in dma_alloc'ed memory, not random user
or special kernel (needed for ppc, also "just the right thing to do").

Some cleanups to make unexpected link transitions less likely to produce
complaints about packet errors, and also to not leave SMA packets stuck and
unable to go out.

A few other random debug and comment cleanups.

Always init rcvhdrq head/tail registers to 0, to avoid race conditions (should
have been that way some time ago).
Signed-off-by: default avatarDave Olson <dave.olson@qlogic.com>
Signed-off-by: default avatarBryan O'Sullivan <bryan.osullivan@qlogic.com>
Cc: "Michael S. Tsirkin" <mst@mellanox.co.il>
Cc: Roland Dreier <rolandd@cisco.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 06993ca6
...@@ -311,6 +311,9 @@ struct ipath_base_info { ...@@ -311,6 +311,9 @@ struct ipath_base_info {
__u32 spi_rcv_egrchunksize; __u32 spi_rcv_egrchunksize;
/* total size of mmap to cover full rcvegrbuffers */ /* total size of mmap to cover full rcvegrbuffers */
__u32 spi_rcv_egrbuftotlen; __u32 spi_rcv_egrbuftotlen;
__u32 spi_filler_for_align;
/* address of readonly memory copy of the rcvhdrq tail register. */
__u64 spi_rcvhdr_tailaddr;
} __attribute__ ((aligned(8))); } __attribute__ ((aligned(8)));
...@@ -380,13 +383,7 @@ struct ipath_user_info { ...@@ -380,13 +383,7 @@ struct ipath_user_info {
*/ */
__u32 spu_rcvhdrsize; __u32 spu_rcvhdrsize;
/* __u64 spu_unused; /* kept for compatible layout */
* cache line aligned (64 byte) user address to
* which the rcvhdrtail register will be written by infinipath
* whenever it changes, so that no chip registers are read in
* the performance path.
*/
__u64 spu_rcvhdraddr;
/* /*
* address of struct base_info to write to * address of struct base_info to write to
......
This diff is collapsed.
...@@ -411,17 +411,8 @@ static int init_pioavailregs(struct ipath_devdata *dd) ...@@ -411,17 +411,8 @@ static int init_pioavailregs(struct ipath_devdata *dd)
/* and its length */ /* and its length */
dd->ipath_freezelen = L1_CACHE_BYTES - sizeof(dd->ipath_statusp[0]); dd->ipath_freezelen = L1_CACHE_BYTES - sizeof(dd->ipath_statusp[0]);
if (dd->ipath_unit * 64 > (IPATH_PORT0_RCVHDRTAIL_SIZE - 64)) {
ipath_dev_err(dd, "unit %u too large for port 0 "
"rcvhdrtail buffer size\n", dd->ipath_unit);
ret = -ENODEV;
}
else
ret = 0; ret = 0;
/* so we can get current tail in ipath_kreceive(), per chip */
dd->ipath_hdrqtailptr = &ipath_port0_rcvhdrtail[
dd->ipath_unit * (64 / sizeof(*ipath_port0_rcvhdrtail))];
done: done:
return ret; return ret;
} }
...@@ -654,7 +645,7 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit) ...@@ -654,7 +645,7 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
{ {
int ret = 0, i; int ret = 0, i;
u32 val32, kpiobufs; u32 val32, kpiobufs;
u64 val, atmp; u64 val;
struct ipath_portdata *pd = NULL; /* keep gcc4 happy */ struct ipath_portdata *pd = NULL; /* keep gcc4 happy */
ret = init_housekeeping(dd, &pd, reinit); ret = init_housekeeping(dd, &pd, reinit);
...@@ -777,24 +768,6 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit) ...@@ -777,24 +768,6 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
goto done; goto done;
} }
val = ipath_port0_rcvhdrtail_dma + dd->ipath_unit * 64;
/* verify that the alignment requirement was met */
ipath_write_kreg_port(dd, dd->ipath_kregs->kr_rcvhdrtailaddr,
0, val);
atmp = ipath_read_kreg64_port(
dd, dd->ipath_kregs->kr_rcvhdrtailaddr, 0);
if (val != atmp) {
ipath_dev_err(dd, "Catastrophic software error, "
"RcvHdrTailAddr0 written as %llx, "
"read back as %llx from %x\n",
(unsigned long long) val,
(unsigned long long) atmp,
dd->ipath_kregs->kr_rcvhdrtailaddr);
ret = -EINVAL;
goto done;
}
ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvbthqp, IPATH_KD_QP); ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvbthqp, IPATH_KD_QP);
/* /*
...@@ -845,12 +818,18 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit) ...@@ -845,12 +818,18 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
* 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.
*/ */
if (reinit) if (reinit) {
ipath_free_pddata(dd, 0, 0); struct ipath_portdata *pd = dd->ipath_pd[0];
dd->ipath_pd[0] = NULL;
ipath_free_pddata(dd, pd);
}
dd->ipath_f_tidtemplate(dd); dd->ipath_f_tidtemplate(dd);
ret = ipath_create_rcvhdrq(dd, pd); ret = ipath_create_rcvhdrq(dd, pd);
if (!ret) if (!ret) {
dd->ipath_hdrqtailptr =
(volatile __le64 *)pd->port_rcvhdrtail_kvaddr;
ret = create_port0_egr(dd); ret = create_port0_egr(dd);
}
if (ret) if (ret)
ipath_dev_err(dd, "failed to allocate port 0 (kernel) " ipath_dev_err(dd, "failed to allocate port 0 (kernel) "
"rcvhdrq and/or egr bufs\n"); "rcvhdrq and/or egr bufs\n");
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include "ips_common.h" #include "ips_common.h"
#include "ipath_layer.h" #include "ipath_layer.h"
/* These are all rcv-related errors which we want to count for stats */
#define E_SUM_PKTERRS \ #define E_SUM_PKTERRS \
(INFINIPATH_E_RHDRLEN | INFINIPATH_E_RBADTID | \ (INFINIPATH_E_RHDRLEN | INFINIPATH_E_RBADTID | \
INFINIPATH_E_RBADVERSION | INFINIPATH_E_RHDR | \ INFINIPATH_E_RBADVERSION | INFINIPATH_E_RHDR | \
...@@ -45,6 +46,7 @@ ...@@ -45,6 +46,7 @@
INFINIPATH_E_RFORMATERR | INFINIPATH_E_RUNSUPVL | \ INFINIPATH_E_RFORMATERR | INFINIPATH_E_RUNSUPVL | \
INFINIPATH_E_RUNEXPCHAR | INFINIPATH_E_REBP) INFINIPATH_E_RUNEXPCHAR | INFINIPATH_E_REBP)
/* These are all send-related errors which we want to count for stats */
#define E_SUM_ERRS \ #define E_SUM_ERRS \
(INFINIPATH_E_SPIOARMLAUNCH | INFINIPATH_E_SUNEXPERRPKTNUM | \ (INFINIPATH_E_SPIOARMLAUNCH | INFINIPATH_E_SUNEXPERRPKTNUM | \
INFINIPATH_E_SDROPPEDDATAPKT | INFINIPATH_E_SDROPPEDSMPPKT | \ INFINIPATH_E_SDROPPEDDATAPKT | INFINIPATH_E_SDROPPEDSMPPKT | \
...@@ -52,6 +54,18 @@ ...@@ -52,6 +54,18 @@
INFINIPATH_E_SMINPKTLEN | INFINIPATH_E_SPKTLEN | \ INFINIPATH_E_SMINPKTLEN | INFINIPATH_E_SPKTLEN | \
INFINIPATH_E_INVALIDADDR) INFINIPATH_E_INVALIDADDR)
/*
* these are errors that can occur when the link changes state while
* a packet is being sent or received. This doesn't cover things
* like EBP or VCRC that can be the result of a sending having the
* link change state, so we receive a "known bad" packet.
*/
#define E_SUM_LINK_PKTERRS \
(INFINIPATH_E_SDROPPEDDATAPKT | INFINIPATH_E_SDROPPEDSMPPKT | \
INFINIPATH_E_SMINPKTLEN | INFINIPATH_E_SPKTLEN | \
INFINIPATH_E_RSHORTPKTLEN | INFINIPATH_E_RMINPKTLEN | \
INFINIPATH_E_RUNEXPCHAR)
static u64 handle_e_sum_errs(struct ipath_devdata *dd, ipath_err_t errs) static u64 handle_e_sum_errs(struct ipath_devdata *dd, ipath_err_t errs)
{ {
unsigned long sbuf[4]; unsigned long sbuf[4];
...@@ -101,9 +115,7 @@ static u64 handle_e_sum_errs(struct ipath_devdata *dd, ipath_err_t errs) ...@@ -101,9 +115,7 @@ static u64 handle_e_sum_errs(struct ipath_devdata *dd, ipath_err_t errs)
if (ipath_debug & __IPATH_PKTDBG) if (ipath_debug & __IPATH_PKTDBG)
printk("\n"); printk("\n");
} }
if ((errs & (INFINIPATH_E_SDROPPEDDATAPKT | if ((errs & E_SUM_LINK_PKTERRS) &&
INFINIPATH_E_SDROPPEDSMPPKT |
INFINIPATH_E_SMINPKTLEN)) &&
!(dd->ipath_flags & IPATH_LINKACTIVE)) { !(dd->ipath_flags & IPATH_LINKACTIVE)) {
/* /*
* This can happen when SMA is trying to bring the link * This can happen when SMA is trying to bring the link
...@@ -112,11 +124,9 @@ static u64 handle_e_sum_errs(struct ipath_devdata *dd, ipath_err_t errs) ...@@ -112,11 +124,9 @@ static u64 handle_e_sum_errs(struct ipath_devdata *dd, ipath_err_t errs)
* valid. We don't want to confuse people, so we just * valid. We don't want to confuse people, so we just
* don't print them, except at debug * don't print them, except at debug
*/ */
ipath_dbg("Ignoring pktsend errors %llx, because not " ipath_dbg("Ignoring packet errors %llx, because link not "
"yet active\n", (unsigned long long) errs); "ACTIVE\n", (unsigned long long) errs);
ignore_this_time = INFINIPATH_E_SDROPPEDDATAPKT | ignore_this_time = errs & E_SUM_LINK_PKTERRS;
INFINIPATH_E_SDROPPEDSMPPKT |
INFINIPATH_E_SMINPKTLEN;
} }
return ignore_this_time; return ignore_this_time;
...@@ -157,7 +167,29 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd, ...@@ -157,7 +167,29 @@ static void handle_e_ibstatuschanged(struct ipath_devdata *dd,
*/ */
val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibcstatus); val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_ibcstatus);
lstate = val & IPATH_IBSTATE_MASK; lstate = val & IPATH_IBSTATE_MASK;
if (lstate == IPATH_IBSTATE_INIT || lstate == IPATH_IBSTATE_ARM ||
/*
* this is confusing enough when it happens that I want to always put it
* on the console and in the logs. If it was a requested state change,
* we'll have already cleared the flags, so we won't print this warning
*/
if ((lstate != IPATH_IBSTATE_ARM && lstate != IPATH_IBSTATE_ACTIVE)
&& (dd->ipath_flags & (IPATH_LINKARMED | IPATH_LINKACTIVE))) {
dev_info(&dd->pcidev->dev, "Link state changed from %s to %s\n",
(dd->ipath_flags & IPATH_LINKARMED) ? "ARM" : "ACTIVE",
ib_linkstate(lstate));
/*
* Flush all queued sends when link went to DOWN or INIT,
* to be sure that they don't block SMA and other MAD packets
*/
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
INFINIPATH_S_ABORT);
ipath_disarm_piobufs(dd, dd->ipath_lastport_piobuf,
(unsigned)(dd->ipath_piobcnt2k +
dd->ipath_piobcnt4k) -
dd->ipath_lastport_piobuf);
}
else if (lstate == IPATH_IBSTATE_INIT || lstate == IPATH_IBSTATE_ARM ||
lstate == IPATH_IBSTATE_ACTIVE) { lstate == IPATH_IBSTATE_ACTIVE) {
/* /*
* only print at SMA if there is a change, debug if not * only print at SMA if there is a change, debug if not
...@@ -380,6 +412,19 @@ static void handle_errors(struct ipath_devdata *dd, ipath_err_t errs) ...@@ -380,6 +412,19 @@ static void handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
if (errs & E_SUM_ERRS) if (errs & E_SUM_ERRS)
ignore_this_time = handle_e_sum_errs(dd, errs); ignore_this_time = handle_e_sum_errs(dd, errs);
else if ((errs & E_SUM_LINK_PKTERRS) &&
!(dd->ipath_flags & IPATH_LINKACTIVE)) {
/*
* This can happen when SMA is trying to bring the link
* up, but the IB link changes state at the "wrong" time.
* The IB logic then complains that the packet isn't
* valid. We don't want to confuse people, so we just
* don't print them, except at debug
*/
ipath_dbg("Ignoring packet errors %llx, because link not "
"ACTIVE\n", (unsigned long long) errs);
ignore_this_time = errs & E_SUM_LINK_PKTERRS;
}
if (supp_msgs == 250000) { if (supp_msgs == 250000) {
/* /*
......
...@@ -62,9 +62,7 @@ struct ipath_portdata { ...@@ -62,9 +62,7 @@ struct ipath_portdata {
/* rcvhdrq base, needs mmap before useful */ /* rcvhdrq base, needs mmap before useful */
void *port_rcvhdrq; void *port_rcvhdrq;
/* kernel virtual address where hdrqtail is updated */ /* kernel virtual address where hdrqtail is updated */
u64 *port_rcvhdrtail_kvaddr; volatile __le64 *port_rcvhdrtail_kvaddr;
/* page * used for uaddr */
struct page *port_rcvhdrtail_pagep;
/* /*
* temp buffer for expected send setup, allocated at open, instead * temp buffer for expected send setup, allocated at open, instead
* of each setup call * of each setup call
...@@ -79,11 +77,7 @@ struct ipath_portdata { ...@@ -79,11 +77,7 @@ struct ipath_portdata {
dma_addr_t port_rcvegr_phys; dma_addr_t port_rcvegr_phys;
/* mmap of hdrq, must fit in 44 bits */ /* mmap of hdrq, must fit in 44 bits */
dma_addr_t port_rcvhdrq_phys; dma_addr_t port_rcvhdrq_phys;
/* dma_addr_t port_rcvhdrqtailaddr_phys;
* the actual user address that we ipath_mlock'ed, so we can
* ipath_munlock it at close
*/
unsigned long port_rcvhdrtail_uaddr;
/* /*
* number of opens on this instance (0 or 1; ignoring forks, dup, * number of opens on this instance (0 or 1; ignoring forks, dup,
* etc. for now) * etc. for now)
...@@ -515,11 +509,6 @@ struct ipath_devdata { ...@@ -515,11 +509,6 @@ struct ipath_devdata {
u8 ipath_lmc; u8 ipath_lmc;
}; };
extern volatile __le64 *ipath_port0_rcvhdrtail;
extern dma_addr_t ipath_port0_rcvhdrtail_dma;
#define IPATH_PORT0_RCVHDRTAIL_SIZE PAGE_SIZE
extern struct list_head ipath_dev_list; extern struct list_head ipath_dev_list;
extern spinlock_t ipath_devs_lock; extern spinlock_t ipath_devs_lock;
extern struct ipath_devdata *ipath_lookup(int unit); extern struct ipath_devdata *ipath_lookup(int unit);
...@@ -579,7 +568,7 @@ void ipath_disarm_piobufs(struct ipath_devdata *, unsigned first, ...@@ -579,7 +568,7 @@ void ipath_disarm_piobufs(struct ipath_devdata *, unsigned first,
unsigned cnt); unsigned cnt);
int ipath_create_rcvhdrq(struct ipath_devdata *, struct ipath_portdata *); int ipath_create_rcvhdrq(struct ipath_devdata *, struct ipath_portdata *);
void ipath_free_pddata(struct ipath_devdata *, u32, int); void ipath_free_pddata(struct ipath_devdata *, struct ipath_portdata *);
int ipath_parse_ushort(const char *str, unsigned short *valp); int ipath_parse_ushort(const char *str, unsigned short *valp);
......
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