diff options
author | Bryan O'Sullivan <bos@pathscale.com> | 2006-07-01 07:36:15 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-07-01 12:56:01 -0400 |
commit | 35783ec07c3f7f6902abe4433e7be1b664d0bbaf (patch) | |
tree | f2bdf80a430862c46cc820b597fcb7cb88c7e777 /drivers | |
parent | 6d8e9dd050ea78862b6c5e2c873ad6407f9b2428 (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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_driver.c | 6 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_file_ops.c | 61 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_init_chip.c | 17 | ||||
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_kernel.h | 2 |
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. |