Commit fce24a9d authored by Dave Olson's avatar Dave Olson Committed by Roland Dreier

IB/qib: Don't mark VL15 bufs as WC to avoid a rare 7322 chip problem

Don't set write combining via PAT on the VL15 buffers to avoid a rare
problem with unaligned writes from interrupt-flushed store buffers.
Signed-off-by: default avatarDave Olson <dave.olson@qlogic.com>
Signed-off-by: default avatarRoland Dreier <rolandd@cisco.com>
parent 67a3e12b
...@@ -686,6 +686,7 @@ struct qib_devdata { ...@@ -686,6 +686,7 @@ struct qib_devdata {
void __iomem *piobase; void __iomem *piobase;
/* mem-mapped pointer to base of user chip regs (if using WC PAT) */ /* mem-mapped pointer to base of user chip regs (if using WC PAT) */
u64 __iomem *userbase; u64 __iomem *userbase;
void __iomem *piovl15base; /* base of VL15 buffers, if not WC */
/* /*
* points to area where PIOavail registers will be DMA'ed. * points to area where PIOavail registers will be DMA'ed.
* Has to be on a page of it's own, because the page will be * Has to be on a page of it's own, because the page will be
......
...@@ -233,6 +233,7 @@ static u32 __iomem *qib_remap_ioaddr32(struct qib_devdata *dd, u32 offset, ...@@ -233,6 +233,7 @@ static u32 __iomem *qib_remap_ioaddr32(struct qib_devdata *dd, u32 offset,
u32 __iomem *krb32 = (u32 __iomem *)dd->kregbase; u32 __iomem *krb32 = (u32 __iomem *)dd->kregbase;
u32 __iomem *map = NULL; u32 __iomem *map = NULL;
u32 cnt = 0; u32 cnt = 0;
u32 tot4k, offs4k;
/* First, simplest case, offset is within the first map. */ /* First, simplest case, offset is within the first map. */
kreglen = (dd->kregend - dd->kregbase) * sizeof(u64); kreglen = (dd->kregend - dd->kregbase) * sizeof(u64);
...@@ -250,7 +251,8 @@ static u32 __iomem *qib_remap_ioaddr32(struct qib_devdata *dd, u32 offset, ...@@ -250,7 +251,8 @@ static u32 __iomem *qib_remap_ioaddr32(struct qib_devdata *dd, u32 offset,
if (dd->userbase) { if (dd->userbase) {
/* If user regs mapped, they are after send, so set limit. */ /* If user regs mapped, they are after send, so set limit. */
u32 ulim = (dd->cfgctxts * dd->ureg_align) + dd->uregbase; u32 ulim = (dd->cfgctxts * dd->ureg_align) + dd->uregbase;
snd_lim = dd->uregbase; if (!dd->piovl15base)
snd_lim = dd->uregbase;
krb32 = (u32 __iomem *)dd->userbase; krb32 = (u32 __iomem *)dd->userbase;
if (offset >= dd->uregbase && offset < ulim) { if (offset >= dd->uregbase && offset < ulim) {
map = krb32 + (offset - dd->uregbase) / sizeof(u32); map = krb32 + (offset - dd->uregbase) / sizeof(u32);
...@@ -277,14 +279,14 @@ static u32 __iomem *qib_remap_ioaddr32(struct qib_devdata *dd, u32 offset, ...@@ -277,14 +279,14 @@ static u32 __iomem *qib_remap_ioaddr32(struct qib_devdata *dd, u32 offset,
/* If 4k buffers exist, account for them by bumping /* If 4k buffers exist, account for them by bumping
* appropriate limit. * appropriate limit.
*/ */
tot4k = dd->piobcnt4k * dd->align4k;
offs4k = dd->piobufbase >> 32;
if (dd->piobcnt4k) { if (dd->piobcnt4k) {
u32 tot4k = dd->piobcnt4k * dd->align4k;
u32 offs4k = dd->piobufbase >> 32;
if (snd_bottom > offs4k) if (snd_bottom > offs4k)
snd_bottom = offs4k; snd_bottom = offs4k;
else { else {
/* 4k above 2k. Bump snd_lim, if needed*/ /* 4k above 2k. Bump snd_lim, if needed*/
if (!dd->userbase) if (!dd->userbase || dd->piovl15base)
snd_lim = offs4k + tot4k; snd_lim = offs4k + tot4k;
} }
} }
...@@ -298,6 +300,15 @@ static u32 __iomem *qib_remap_ioaddr32(struct qib_devdata *dd, u32 offset, ...@@ -298,6 +300,15 @@ static u32 __iomem *qib_remap_ioaddr32(struct qib_devdata *dd, u32 offset,
cnt = snd_lim - offset; cnt = snd_lim - offset;
} }
if (!map && offs4k && dd->piovl15base) {
snd_lim = offs4k + tot4k + 2 * dd->align4k;
if (offset >= (offs4k + tot4k) && offset < snd_lim) {
map = (u32 __iomem *)dd->piovl15base +
((offset - (offs4k + tot4k)) / sizeof(u32));
cnt = snd_lim - offset;
}
}
mapped: mapped:
if (cntp) if (cntp)
*cntp = cnt; *cntp = cnt;
......
...@@ -6119,9 +6119,25 @@ static int qib_init_7322_variables(struct qib_devdata *dd) ...@@ -6119,9 +6119,25 @@ static int qib_init_7322_variables(struct qib_devdata *dd)
qib_set_ctxtcnt(dd); qib_set_ctxtcnt(dd);
if (qib_wc_pat) { if (qib_wc_pat) {
ret = init_chip_wc_pat(dd, NUM_VL15_BUFS * dd->align4k); resource_size_t vl15off;
/*
* We do not set WC on the VL15 buffers to avoid
* a rare problem with unaligned writes from
* interrupt-flushed store buffers, so we need
* to map those separately here. We can't solve
* this for the rarely used mtrr case.
*/
ret = init_chip_wc_pat(dd, 0);
if (ret) if (ret)
goto bail; goto bail;
/* vl15 buffers start just after the 4k buffers */
vl15off = dd->physaddr + (dd->piobufbase >> 32) +
dd->piobcnt4k * dd->align4k;
dd->piovl15base = ioremap_nocache(vl15off,
NUM_VL15_BUFS * dd->align4k);
if (!dd->piovl15base)
goto bail;
} }
qib_7322_set_baseaddrs(dd); /* set chip access pointers now */ qib_7322_set_baseaddrs(dd); /* set chip access pointers now */
......
...@@ -1499,6 +1499,12 @@ int qib_setup_eagerbufs(struct qib_ctxtdata *rcd) ...@@ -1499,6 +1499,12 @@ int qib_setup_eagerbufs(struct qib_ctxtdata *rcd)
return -ENOMEM; return -ENOMEM;
} }
/*
* Note: Changes to this routine should be mirrored
* for the diagnostics routine qib_remap_ioaddr32().
* There is also related code for VL15 buffers in qib_init_7322_variables().
* The teardown code that unmaps is in qib_pcie_ddcleanup()
*/
int init_chip_wc_pat(struct qib_devdata *dd, u32 vl15buflen) int init_chip_wc_pat(struct qib_devdata *dd, u32 vl15buflen)
{ {
u64 __iomem *qib_kregbase = NULL; u64 __iomem *qib_kregbase = NULL;
......
...@@ -179,6 +179,8 @@ void qib_pcie_ddcleanup(struct qib_devdata *dd) ...@@ -179,6 +179,8 @@ void qib_pcie_ddcleanup(struct qib_devdata *dd)
iounmap(dd->piobase); iounmap(dd->piobase);
if (dd->userbase) if (dd->userbase)
iounmap(dd->userbase); iounmap(dd->userbase);
if (dd->piovl15base)
iounmap(dd->piovl15base);
pci_disable_device(dd->pcidev); pci_disable_device(dd->pcidev);
pci_release_regions(dd->pcidev); pci_release_regions(dd->pcidev);
......
...@@ -340,9 +340,13 @@ u32 __iomem *qib_getsendbuf_range(struct qib_devdata *dd, u32 *pbufnum, ...@@ -340,9 +340,13 @@ u32 __iomem *qib_getsendbuf_range(struct qib_devdata *dd, u32 *pbufnum,
if (i < dd->piobcnt2k) if (i < dd->piobcnt2k)
buf = (u32 __iomem *)(dd->pio2kbase + buf = (u32 __iomem *)(dd->pio2kbase +
i * dd->palign); i * dd->palign);
else else if (i < dd->piobcnt2k + dd->piobcnt4k || !dd->piovl15base)
buf = (u32 __iomem *)(dd->pio4kbase + buf = (u32 __iomem *)(dd->pio4kbase +
(i - dd->piobcnt2k) * dd->align4k); (i - dd->piobcnt2k) * dd->align4k);
else
buf = (u32 __iomem *)(dd->piovl15base +
(i - (dd->piobcnt2k + dd->piobcnt4k)) *
dd->align4k);
if (pbufnum) if (pbufnum)
*pbufnum = i; *pbufnum = i;
dd->upd_pio_shadow = 0; dd->upd_pio_shadow = 0;
......
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