aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBryan O'Sullivan <bos@pathscale.com>2006-07-01 07:36:15 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-07-01 12:56:01 -0400
commit35783ec07c3f7f6902abe4433e7be1b664d0bbaf (patch)
treef2bdf80a430862c46cc820b597fcb7cb88c7e777
parent6d8e9dd050ea78862b6c5e2c873ad6407f9b2428 (diff)
[PATCH] IB/ipath: fix a bug that results in addresses near 0 being written via DMA
We can't tell for sure if any packets are in the infinipath receive buffer when we shut down a chip port. Normally this is taken care of by orderly shutdown, but when processes are terminated, or sending process has a bug, we can continue to receive packets. So rather than writing zero to the address registers for the closing port, we point it at a dummy memory. Signed-off-by: Dave Olson <dave.olson@qlogic.com> Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com> Cc: "Michael S. Tsirkin" <mst@mellanox.co.il> Cc: Roland Dreier <rolandd@cisco.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--drivers/infiniband/hw/ipath/ipath_driver.c6
-rw-r--r--drivers/infiniband/hw/ipath/ipath_file_ops.c61
-rw-r--r--drivers/infiniband/hw/ipath/ipath_init_chip.c17
-rw-r--r--drivers/infiniband/hw/ipath/ipath_kernel.h2
4 files changed, 60 insertions, 26 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c
index 4109913c20a7..f647918db62b 100644
--- a/drivers/infiniband/hw/ipath/ipath_driver.c
+++ b/drivers/infiniband/hw/ipath/ipath_driver.c
@@ -1824,6 +1824,12 @@ static void cleanup_device(struct ipath_devdata *dd)
1824 dd->ipath_pioavailregs_phys); 1824 dd->ipath_pioavailregs_phys);
1825 dd->ipath_pioavailregs_dma = NULL; 1825 dd->ipath_pioavailregs_dma = NULL;
1826 } 1826 }
1827 if (dd->ipath_dummy_hdrq) {
1828 dma_free_coherent(&dd->pcidev->dev,
1829 dd->ipath_pd[0]->port_rcvhdrq_size,
1830 dd->ipath_dummy_hdrq, dd->ipath_dummy_hdrq_phys);
1831 dd->ipath_dummy_hdrq = NULL;
1832 }
1827 1833
1828 if (dd->ipath_pageshadow) { 1834 if (dd->ipath_pageshadow) {
1829 struct page **tmpp = dd->ipath_pageshadow; 1835 struct page **tmpp = dd->ipath_pageshadow;
diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c
index e89d3a17acd9..51a609d47087 100644
--- a/drivers/infiniband/hw/ipath/ipath_file_ops.c
+++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c
@@ -1486,42 +1486,51 @@ static int ipath_close(struct inode *in, struct file *fp)
1486 } 1486 }
1487 1487
1488 if (dd->ipath_kregbase) { 1488 if (dd->ipath_kregbase) {
1489 ipath_write_kreg_port( 1489 int i;
1490 dd, dd->ipath_kregs->kr_rcvhdrtailaddr, 1490 /* atomically clear receive enable port. */
1491 port, 0ULL); 1491 clear_bit(INFINIPATH_R_PORTENABLE_SHIFT + port,
1492 ipath_write_kreg_port( 1492 &dd->ipath_rcvctrl);
1493 dd, dd->ipath_kregs->kr_rcvhdraddr, 1493 ipath_write_kreg( dd, dd->ipath_kregs->kr_rcvctrl,
1494 pd->port_port, 0); 1494 dd->ipath_rcvctrl);
1495 /* and read back from chip to be sure that nothing
1496 * else is in flight when we do the rest */
1497 (void)ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
1495 1498
1496 /* clean up the pkeys for this port user */ 1499 /* clean up the pkeys for this port user */
1497 ipath_clean_part_key(pd, dd); 1500 ipath_clean_part_key(pd, dd);
1498 1501
1499 if (port < dd->ipath_cfgports) {
1500 int i = dd->ipath_pbufsport * (port - 1);
1501 ipath_disarm_piobufs(dd, i, dd->ipath_pbufsport);
1502 1502
1503 /* atomically clear receive enable port. */ 1503 /*
1504 clear_bit(INFINIPATH_R_PORTENABLE_SHIFT + port, 1504 * be paranoid, and never write 0's to these, just use an
1505 &dd->ipath_rcvctrl); 1505 * unused part of the port 0 tail page. Of course,
1506 ipath_write_kreg( 1506 * rcvhdraddr points to a large chunk of memory, so this
1507 dd, 1507 * could still trash things, but at least it won't trash
1508 dd->ipath_kregs->kr_rcvctrl, 1508 * page 0, and by disabling the port, it should stop "soon",
1509 dd->ipath_rcvctrl); 1509 * even if a packet or two is in already in flight after we
1510 1510 * disabled the port.
1511 if (dd->ipath_pageshadow) 1511 */
1512 unlock_expected_tids(pd); 1512 ipath_write_kreg_port(dd,
1513 ipath_stats.sps_ports--; 1513 dd->ipath_kregs->kr_rcvhdrtailaddr, port,
1514 ipath_cdbg(PROC, "%s[%u] closed port %u:%u\n", 1514 dd->ipath_dummy_hdrq_phys);
1515 pd->port_comm, pd->port_pid, 1515 ipath_write_kreg_port(dd, dd->ipath_kregs->kr_rcvhdraddr,
1516 dd->ipath_unit, port); 1516 pd->port_port, dd->ipath_dummy_hdrq_phys);
1517 } 1517
1518 i = dd->ipath_pbufsport * (port - 1);
1519 ipath_disarm_piobufs(dd, i, dd->ipath_pbufsport);
1520
1521 if (dd->ipath_pageshadow)
1522 unlock_expected_tids(pd);
1523 ipath_stats.sps_ports--;
1524 ipath_cdbg(PROC, "%s[%u] closed port %u:%u\n",
1525 pd->port_comm, pd->port_pid,
1526 dd->ipath_unit, port);
1527
1528 dd->ipath_f_clear_tids(dd, pd->port_port);
1518 } 1529 }
1519 1530
1520 pd->port_cnt = 0; 1531 pd->port_cnt = 0;
1521 pd->port_pid = 0; 1532 pd->port_pid = 0;
1522 1533
1523 dd->ipath_f_clear_tids(dd, pd->port_port);
1524
1525 dd->ipath_pd[pd->port_port] = NULL; /* before releasing mutex */ 1534 dd->ipath_pd[pd->port_port] = NULL; /* before releasing mutex */
1526 mutex_unlock(&ipath_mutex); 1535 mutex_unlock(&ipath_mutex);
1527 ipath_free_pddata(dd, pd); /* after releasing the mutex */ 1536 ipath_free_pddata(dd, pd); /* after releasing the mutex */
diff --git a/drivers/infiniband/hw/ipath/ipath_init_chip.c b/drivers/infiniband/hw/ipath/ipath_init_chip.c
index 9faa201abe8e..ff322e5c14c8 100644
--- a/drivers/infiniband/hw/ipath/ipath_init_chip.c
+++ b/drivers/infiniband/hw/ipath/ipath_init_chip.c
@@ -647,6 +647,7 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
647 u32 val32, kpiobufs; 647 u32 val32, kpiobufs;
648 u64 val; 648 u64 val;
649 struct ipath_portdata *pd = NULL; /* keep gcc4 happy */ 649 struct ipath_portdata *pd = NULL; /* keep gcc4 happy */
650 gfp_t gfp_flags = GFP_USER | __GFP_COMP;
650 651
651 ret = init_housekeeping(dd, &pd, reinit); 652 ret = init_housekeeping(dd, &pd, reinit);
652 if (ret) 653 if (ret)
@@ -834,6 +835,22 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
834 else 835 else
835 enable_chip(dd, pd, reinit); 836 enable_chip(dd, pd, reinit);
836 837
838
839 if (!ret && !reinit) {
840 /* used when we close a port, for DMA already in flight at close */
841 dd->ipath_dummy_hdrq = dma_alloc_coherent(
842 &dd->pcidev->dev, pd->port_rcvhdrq_size,
843 &dd->ipath_dummy_hdrq_phys,
844 gfp_flags);
845 if (!dd->ipath_dummy_hdrq ) {
846 dev_info(&dd->pcidev->dev,
847 "Couldn't allocate 0x%lx bytes for dummy hdrq\n",
848 pd->port_rcvhdrq_size);
849 /* fallback to just 0'ing */
850 dd->ipath_dummy_hdrq_phys = 0UL;
851 }
852 }
853
837 /* 854 /*
838 * cause retrigger of pending interrupts ignored during init, 855 * cause retrigger of pending interrupts ignored during init,
839 * even if we had errors 856 * even if we had errors
diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h
index 00a6bbdbe957..e9f374fb641e 100644
--- a/drivers/infiniband/hw/ipath/ipath_kernel.h
+++ b/drivers/infiniband/hw/ipath/ipath_kernel.h
@@ -352,6 +352,8 @@ struct ipath_devdata {
352 /* check for stale messages in rcv queue */ 352 /* check for stale messages in rcv queue */
353 /* only allow one intr at a time. */ 353 /* only allow one intr at a time. */
354 unsigned long ipath_rcv_pending; 354 unsigned long ipath_rcv_pending;
355 void *ipath_dummy_hdrq; /* used after port close */
356 dma_addr_t ipath_dummy_hdrq_phys;
355 357
356 /* 358 /*
357 * Shadow copies of registers; size indicates read access size. 359 * Shadow copies of registers; size indicates read access size.