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 <[EMAIL PROTECTED]>
Signed-off-by: Bryan O'Sullivan <[EMAIL PROTECTED]>

diff -r a7c1ad1e090b -r b6ebaf2dd2fd drivers/infiniband/hw/ipath/ipath_driver.c
--- a/drivers/infiniband/hw/ipath/ipath_driver.c        Thu Jun 29 14:33:26 
2006 -0700
+++ b/drivers/infiniband/hw/ipath/ipath_driver.c        Thu Jun 29 14:33:26 
2006 -0700
@@ -1824,6 +1824,12 @@ static void cleanup_device(struct ipath_
                                  dd->ipath_pioavailregs_phys);
                dd->ipath_pioavailregs_dma = NULL;
        }
+       if (dd->ipath_dummy_hdrq) {
+               dma_free_coherent(&dd->pcidev->dev,
+                       dd->ipath_pd[0]->port_rcvhdrq_size,
+                       dd->ipath_dummy_hdrq, dd->ipath_dummy_hdrq_phys);
+               dd->ipath_dummy_hdrq = NULL;
+       }
 
        if (dd->ipath_pageshadow) {
                struct page **tmpp = dd->ipath_pageshadow;
diff -r a7c1ad1e090b -r b6ebaf2dd2fd 
drivers/infiniband/hw/ipath/ipath_file_ops.c
--- a/drivers/infiniband/hw/ipath/ipath_file_ops.c      Thu Jun 29 14:33:26 
2006 -0700
+++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c      Thu Jun 29 14:33:26 
2006 -0700
@@ -1486,41 +1486,50 @@ static int ipath_close(struct inode *in,
        }
 
        if (dd->ipath_kregbase) {
-               ipath_write_kreg_port(
-                       dd, dd->ipath_kregs->kr_rcvhdrtailaddr,
-                       port, 0ULL);
-               ipath_write_kreg_port(
-                       dd, dd->ipath_kregs->kr_rcvhdraddr,
-                       pd->port_port, 0);
+               int i;
+               /* atomically clear receive enable port. */
+               clear_bit(INFINIPATH_R_PORTENABLE_SHIFT + port,
+                         &dd->ipath_rcvctrl);
+               ipath_write_kreg( dd, dd->ipath_kregs->kr_rcvctrl,
+                       dd->ipath_rcvctrl);
+               /* and read back from chip to be sure that nothing
+                * else is in flight when we do the rest */
+               (void)ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
 
                /* clean up the pkeys for this port user */
                ipath_clean_part_key(pd, dd);
 
-               if (port < dd->ipath_cfgports) {
-                       int i = dd->ipath_pbufsport * (port - 1);
-                       ipath_disarm_piobufs(dd, i, dd->ipath_pbufsport);
-
-                       /* atomically clear receive enable port. */
-                       clear_bit(INFINIPATH_R_PORTENABLE_SHIFT + port,
-                                 &dd->ipath_rcvctrl);
-                       ipath_write_kreg(
-                               dd,
-                               dd->ipath_kregs->kr_rcvctrl,
-                               dd->ipath_rcvctrl);
-
-                       if (dd->ipath_pageshadow)
-                               unlock_expected_tids(pd);
-                       ipath_stats.sps_ports--;
-                       ipath_cdbg(PROC, "%s[%u] closed port %u:%u\n",
-                                  pd->port_comm, pd->port_pid,
-                                  dd->ipath_unit, port);
-               }
+
+               /*
+                * be paranoid, and never write 0's to these, just use an
+                * unused part of the port 0 tail page.  Of course,
+                * rcvhdraddr points to a large chunk of memory, so this
+                * could still trash things, but at least it won't trash
+                * page 0, and by disabling the port, it should stop "soon",
+                * even if a packet or two is in already in flight after we
+                * disabled the port.
+                */
+               ipath_write_kreg_port(dd,
+                       dd->ipath_kregs->kr_rcvhdrtailaddr, port,
+                       dd->ipath_dummy_hdrq_phys);
+               ipath_write_kreg_port(dd, dd->ipath_kregs->kr_rcvhdraddr,
+                       pd->port_port, dd->ipath_dummy_hdrq_phys);
+
+               i = dd->ipath_pbufsport * (port - 1);
+               ipath_disarm_piobufs(dd, i, dd->ipath_pbufsport);
+
+               if (dd->ipath_pageshadow)
+                       unlock_expected_tids(pd);
+               ipath_stats.sps_ports--;
+               ipath_cdbg(PROC, "%s[%u] closed port %u:%u\n",
+                          pd->port_comm, pd->port_pid,
+                          dd->ipath_unit, port);
+
+               dd->ipath_f_clear_tids(dd, pd->port_port);
        }
 
        pd->port_cnt = 0;
        pd->port_pid = 0;
-
-       dd->ipath_f_clear_tids(dd, pd->port_port);
 
        dd->ipath_pd[pd->port_port] = NULL; /* before releasing mutex */
        mutex_unlock(&ipath_mutex);
diff -r a7c1ad1e090b -r b6ebaf2dd2fd 
drivers/infiniband/hw/ipath/ipath_init_chip.c
--- a/drivers/infiniband/hw/ipath/ipath_init_chip.c     Thu Jun 29 14:33:26 
2006 -0700
+++ b/drivers/infiniband/hw/ipath/ipath_init_chip.c     Thu Jun 29 14:33:26 
2006 -0700
@@ -647,6 +647,7 @@ int ipath_init_chip(struct ipath_devdata
        u32 val32, kpiobufs;
        u64 val;
        struct ipath_portdata *pd = NULL; /* keep gcc4 happy */
+       gfp_t gfp_flags = GFP_USER | __GFP_COMP;
 
        ret = init_housekeeping(dd, &pd, reinit);
        if (ret)
@@ -833,6 +834,22 @@ int ipath_init_chip(struct ipath_devdata
                              "rcvhdrq and/or egr bufs\n");
        else
                enable_chip(dd, pd, reinit);
+
+
+       if (!ret && !reinit) {
+           /* used when we close a port, for DMA already in flight at close */
+               dd->ipath_dummy_hdrq = dma_alloc_coherent(
+                       &dd->pcidev->dev, pd->port_rcvhdrq_size,
+                       &dd->ipath_dummy_hdrq_phys,
+                       gfp_flags);
+               if (!dd->ipath_dummy_hdrq ) {
+                       dev_info(&dd->pcidev->dev,
+                               "Couldn't allocate 0x%lx bytes for dummy 
hdrq\n",
+                               pd->port_rcvhdrq_size);
+                       /* fallback to just 0'ing */
+                       dd->ipath_dummy_hdrq_phys = 0UL;
+               }
+       }
 
        /*
         * cause retrigger of pending interrupts ignored during init,
diff -r a7c1ad1e090b -r b6ebaf2dd2fd drivers/infiniband/hw/ipath/ipath_kernel.h
--- a/drivers/infiniband/hw/ipath/ipath_kernel.h        Thu Jun 29 14:33:26 
2006 -0700
+++ b/drivers/infiniband/hw/ipath/ipath_kernel.h        Thu Jun 29 14:33:26 
2006 -0700
@@ -352,6 +352,8 @@ struct ipath_devdata {
        /* check for stale messages in rcv queue */
        /* only allow one intr at a time. */
        unsigned long ipath_rcv_pending;
+       void *ipath_dummy_hdrq; /* used after port close */
+       dma_addr_t ipath_dummy_hdrq_phys;
 
        /*
         * Shadow copies of registers; size indicates read access size.
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to