From c529aa30337b928bd6bc34293608cb3d4505856e Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Fri, 6 Sep 2013 16:51:16 -0700 Subject: NTB: Xeon Doorbell errata workaround Modifications to the 14th bit of the B2BDOORBELL register will not be mirrored to the remote system due to a hardware issue. To get around the issue, shrink the number of available doorbell bits by 1. The max number of doorbells was being used as a way to referencing the Link Doorbell bit. Since this would no longer work, the driver must now explicitly reference that bit. This does not affect the xeon_errata_workaround case, as it is not using the b2bdoorbell register. Signed-off-by: Jon Mason --- drivers/ntb/ntb_hw.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) (limited to 'drivers/ntb/ntb_hw.c') diff --git a/drivers/ntb/ntb_hw.c b/drivers/ntb/ntb_hw.c index 1cb6e51..6c9d733 100644 --- a/drivers/ntb/ntb_hw.c +++ b/drivers/ntb/ntb_hw.c @@ -678,6 +678,7 @@ static int ntb_xeon_setup(struct ntb_device *ndev) return -EINVAL; ndev->limits.max_mw = SNB_ERRATA_MAX_MW; + ndev->limits.max_db_bits = SNB_MAX_DB_BITS; ndev->reg_ofs.spad_write = ndev->mw[1].vbase + SNB_SPAD_OFFSET; ndev->reg_ofs.rdb = ndev->mw[1].vbase + @@ -690,6 +691,13 @@ static int ntb_xeon_setup(struct ntb_device *ndev) SNB_PBAR4LMT_OFFSET); } else { ndev->limits.max_mw = SNB_MAX_MW; + + /* HW Errata on bit 14 of b2bdoorbell register. Writes + * will not be mirrored to the remote system. Shrink + * the number of bits by one, since bit 14 is the last + * bit. + */ + ndev->limits.max_db_bits = SNB_MAX_DB_BITS - 1; ndev->reg_ofs.spad_write = ndev->reg_base + SNB_B2B_SPAD_OFFSET; ndev->reg_ofs.rdb = ndev->reg_base + @@ -769,6 +777,7 @@ static int ntb_xeon_setup(struct ntb_device *ndev) * have an equal amount. */ ndev->limits.max_spads = SNB_MAX_COMPAT_SPADS / 2; + ndev->limits.max_db_bits = SNB_MAX_DB_BITS; /* Note: The SDOORBELL is the cause of the errata. You REALLY * don't want to touch it. */ @@ -793,6 +802,7 @@ static int ntb_xeon_setup(struct ntb_device *ndev) * have an equal amount. */ ndev->limits.max_spads = SNB_MAX_COMPAT_SPADS / 2; + ndev->limits.max_db_bits = SNB_MAX_DB_BITS; ndev->reg_ofs.rdb = ndev->reg_base + SNB_PDOORBELL_OFFSET; ndev->reg_ofs.ldb = ndev->reg_base + SNB_SDOORBELL_OFFSET; ndev->reg_ofs.ldb_mask = ndev->reg_base + SNB_SDBMSK_OFFSET; @@ -819,7 +829,6 @@ static int ntb_xeon_setup(struct ntb_device *ndev) ndev->reg_ofs.lnk_stat = ndev->reg_base + SNB_SLINK_STATUS_OFFSET; ndev->reg_ofs.spci_cmd = ndev->reg_base + SNB_PCICMD_OFFSET; - ndev->limits.max_db_bits = SNB_MAX_DB_BITS; ndev->limits.msix_cnt = SNB_MSIX_CNT; ndev->bits_per_vector = SNB_DB_BITS_PER_VEC; @@ -986,7 +995,7 @@ static irqreturn_t xeon_event_msix_irq(int irq, void *dev) dev_err(&ndev->pdev->dev, "Error determining link status\n"); /* bit 15 is always the link bit */ - writew(1 << ndev->limits.max_db_bits, ndev->reg_ofs.ldb); + writew(1 << SNB_LINK_DB, ndev->reg_ofs.ldb); return IRQ_HANDLED; } @@ -1176,9 +1185,10 @@ static int ntb_setup_interrupts(struct ntb_device *ndev) */ if (ndev->hw_type == BWD_HW) writeq(~0, ndev->reg_ofs.ldb_mask); - else - writew(~(1 << ndev->limits.max_db_bits), - ndev->reg_ofs.ldb_mask); + else { + u16 var = 1 << SNB_LINK_DB; + writew(~var, ndev->reg_ofs.ldb_mask); + } rc = ntb_setup_msix(ndev); if (!rc) -- cgit v1.1 From 9fec60c41416c9c40ec520bb79064345d2396632 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Fri, 13 Sep 2013 17:05:23 -0700 Subject: NTB: Fix NTB-RP Link Up The Xeon NTB-RP setup, the transparent side does not get a link up/down interrupt. Since the presence of a NTB device on the transparent side means that we have a NTB link up, we can work around the lack of an interrupt by simply calling the link up function to notify the upper layers. Signed-off-by: Jon Mason --- drivers/ntb/ntb_hw.c | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) (limited to 'drivers/ntb/ntb_hw.c') diff --git a/drivers/ntb/ntb_hw.c b/drivers/ntb/ntb_hw.c index 6c9d733..a9b065f 100644 --- a/drivers/ntb/ntb_hw.c +++ b/drivers/ntb/ntb_hw.c @@ -1296,6 +1296,32 @@ static void ntb_free_debugfs(struct ntb_device *ndev) } } +static void ntb_hw_link_up(struct ntb_device *ndev) +{ + if (ndev->conn_type == NTB_CONN_TRANSPARENT) + ntb_link_event(ndev, NTB_LINK_UP); + else + /* Let's bring the NTB link up */ + writel(NTB_CNTL_BAR23_SNOOP | NTB_CNTL_BAR45_SNOOP, + ndev->reg_ofs.lnk_cntl); +} + +static void ntb_hw_link_down(struct ntb_device *ndev) +{ + u32 ntb_cntl; + + if (ndev->conn_type == NTB_CONN_TRANSPARENT) { + ntb_link_event(ndev, NTB_LINK_DOWN); + return; + } + + /* Bring NTB link down */ + ntb_cntl = readl(ndev->reg_ofs.lnk_cntl); + ntb_cntl &= ~(NTB_CNTL_BAR23_SNOOP | NTB_CNTL_BAR45_SNOOP); + ntb_cntl |= NTB_CNTL_LINK_DISABLE; + writel(ntb_cntl, ndev->reg_ofs.lnk_cntl); +} + static int ntb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct ntb_device *ndev; @@ -1384,9 +1410,7 @@ static int ntb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (rc) goto err6; - /* Let's bring the NTB link up */ - writel(NTB_CNTL_BAR23_SNOOP | NTB_CNTL_BAR45_SNOOP, - ndev->reg_ofs.lnk_cntl); + ntb_hw_link_up(ndev); return 0; @@ -1416,12 +1440,8 @@ static void ntb_pci_remove(struct pci_dev *pdev) { struct ntb_device *ndev = pci_get_drvdata(pdev); int i; - u32 ntb_cntl; - /* Bring NTB link down */ - ntb_cntl = readl(ndev->reg_ofs.lnk_cntl); - ntb_cntl |= NTB_CNTL_LINK_DISABLE; - writel(ntb_cntl, ndev->reg_ofs.lnk_cntl); + ntb_hw_link_down(ndev); ntb_transport_free(ndev->ntb_transport); -- cgit v1.1 From 9739047380a4a1a9f3eba4deea2f5978703b4ecb Mon Sep 17 00:00:00 2001 From: Alexander Gordeev Date: Wed, 2 Oct 2013 12:49:09 +0200 Subject: ntb: Fix missed call to pci_enable_msix() Current MSI-X enablement code assumes MSI-Xs were successfully allocated in case less than requested vectors were available. That assumption is wrong, since MSI-Xs should be enabled with a repeated call to pci_enable_msix(). This update fixes this. Signed-off-by: Alexander Gordeev Signed-off-by: Jon Mason --- drivers/ntb/ntb_hw.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/ntb/ntb_hw.c') diff --git a/drivers/ntb/ntb_hw.c b/drivers/ntb/ntb_hw.c index a9b065f..fa97948 100644 --- a/drivers/ntb/ntb_hw.c +++ b/drivers/ntb/ntb_hw.c @@ -1084,6 +1084,10 @@ static int ntb_setup_msix(struct ntb_device *ndev) "Only %d MSI-X vectors. Limiting the number of queues to that number.\n", rc); msix_entries = rc; + + rc = pci_enable_msix(pdev, ndev->msix_entries, msix_entries); + if (rc) + goto err1; } for (i = 0; i < msix_entries; i++) { -- cgit v1.1 From 58b889206ea4ba75a57986e223da647f91ba1a19 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Fri, 1 Nov 2013 15:08:19 -0700 Subject: NTB: Document HW errata Add a comment describing the necessary ordering of modifications to the NTB Limit and Base registers. Signed-off-by: Jon Mason --- drivers/ntb/ntb_hw.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers/ntb/ntb_hw.c') diff --git a/drivers/ntb/ntb_hw.c b/drivers/ntb/ntb_hw.c index fa97948..391c377 100644 --- a/drivers/ntb/ntb_hw.c +++ b/drivers/ntb/ntb_hw.c @@ -689,6 +689,12 @@ static int ntb_xeon_setup(struct ntb_device *ndev) */ writeq(ndev->mw[1].bar_sz + 0x1000, ndev->reg_base + SNB_PBAR4LMT_OFFSET); + /* HW errata on the Limit registers. They can only be + * written when the base register is 4GB aligned and + * < 32bit. This should already be the case based on the + * driver defaults, but write the Limit registers first + * just in case. + */ } else { ndev->limits.max_mw = SNB_MAX_MW; @@ -707,6 +713,12 @@ static int ntb_xeon_setup(struct ntb_device *ndev) * something silly */ writeq(0, ndev->reg_base + SNB_PBAR4LMT_OFFSET); + /* HW errata on the Limit registers. They can only be + * written when the base register is 4GB aligned and + * < 32bit. This should already be the case based on the + * driver defaults, but write the Limit registers first + * just in case. + */ } /* The Xeon errata workaround requires setting SBAR Base -- cgit v1.1 From 78958433db077b339f3a039890148561086574e4 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Thu, 3 Oct 2013 17:24:03 -0700 Subject: NTB: Enable Snoop on Primary Side Enable Snoop from Primary to Secondary side on BAR23 and BAR45 on all TLPs. Previously, Snoop was only enabled from Secondary to Primary side. This can have a performance improvement on some workloads. Also, make the code more obvious about how the link is being enabled. Signed-off-by: Jon Mason --- drivers/ntb/ntb_hw.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'drivers/ntb/ntb_hw.c') diff --git a/drivers/ntb/ntb_hw.c b/drivers/ntb/ntb_hw.c index 391c377..80505ae 100644 --- a/drivers/ntb/ntb_hw.c +++ b/drivers/ntb/ntb_hw.c @@ -1316,10 +1316,16 @@ static void ntb_hw_link_up(struct ntb_device *ndev) { if (ndev->conn_type == NTB_CONN_TRANSPARENT) ntb_link_event(ndev, NTB_LINK_UP); - else + else { + u32 ntb_cntl; + /* Let's bring the NTB link up */ - writel(NTB_CNTL_BAR23_SNOOP | NTB_CNTL_BAR45_SNOOP, - ndev->reg_ofs.lnk_cntl); + ntb_cntl = readl(ndev->reg_ofs.lnk_cntl); + ntb_cntl &= ~(NTB_CNTL_LINK_DISABLE | NTB_CNTL_CFG_LOCK); + ntb_cntl |= NTB_CNTL_P2S_BAR23_SNOOP | NTB_CNTL_S2P_BAR23_SNOOP; + ntb_cntl |= NTB_CNTL_P2S_BAR45_SNOOP | NTB_CNTL_S2P_BAR45_SNOOP; + writel(ntb_cntl, ndev->reg_ofs.lnk_cntl); + } } static void ntb_hw_link_down(struct ntb_device *ndev) @@ -1333,8 +1339,9 @@ static void ntb_hw_link_down(struct ntb_device *ndev) /* Bring NTB link down */ ntb_cntl = readl(ndev->reg_ofs.lnk_cntl); - ntb_cntl &= ~(NTB_CNTL_BAR23_SNOOP | NTB_CNTL_BAR45_SNOOP); - ntb_cntl |= NTB_CNTL_LINK_DISABLE; + ntb_cntl &= ~(NTB_CNTL_P2S_BAR23_SNOOP | NTB_CNTL_S2P_BAR23_SNOOP); + ntb_cntl &= ~(NTB_CNTL_P2S_BAR45_SNOOP | NTB_CNTL_S2P_BAR45_SNOOP); + ntb_cntl |= NTB_CNTL_LINK_DISABLE | NTB_CNTL_CFG_LOCK; writel(ntb_cntl, ndev->reg_ofs.lnk_cntl); } -- cgit v1.1 From e8aeb60c389c2aa48d345bcf717f8cb7edf67680 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Thu, 18 Apr 2013 17:59:44 -0700 Subject: NTB: Disable interrupts and poll under high load Disable interrupts and poll under high load Signed-off-by: Jon Mason --- drivers/ntb/ntb_hw.c | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) (limited to 'drivers/ntb/ntb_hw.c') diff --git a/drivers/ntb/ntb_hw.c b/drivers/ntb/ntb_hw.c index 80505ae..170e8e60 100644 --- a/drivers/ntb/ntb_hw.c +++ b/drivers/ntb/ntb_hw.c @@ -141,6 +141,24 @@ void ntb_unregister_event_callback(struct ntb_device *ndev) ndev->event_cb = NULL; } +static void ntb_irq_work(unsigned long data) +{ + struct ntb_db_cb *db_cb = (struct ntb_db_cb *)data; + int rc; + + rc = db_cb->callback(db_cb->data, db_cb->db_num); + if (rc) + tasklet_schedule(&db_cb->irq_work); + else { + struct ntb_device *ndev = db_cb->ndev; + unsigned long mask; + + mask = readw(ndev->reg_ofs.ldb_mask); + clear_bit(db_cb->db_num * ndev->bits_per_vector, &mask); + writew(mask, ndev->reg_ofs.ldb_mask); + } +} + /** * ntb_register_db_callback() - register a callback for doorbell interrupt * @ndev: pointer to ntb_device instance @@ -155,7 +173,7 @@ void ntb_unregister_event_callback(struct ntb_device *ndev) * RETURNS: An appropriate -ERRNO error value on error, or zero for success. */ int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx, - void *data, void (*func)(void *data, int db_num)) + void *data, int (*func)(void *data, int db_num)) { unsigned long mask; @@ -166,6 +184,10 @@ int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx, ndev->db_cb[idx].callback = func; ndev->db_cb[idx].data = data; + ndev->db_cb[idx].ndev = ndev; + + tasklet_init(&ndev->db_cb[idx].irq_work, ntb_irq_work, + (unsigned long) &ndev->db_cb[idx]); /* unmask interrupt */ mask = readw(ndev->reg_ofs.ldb_mask); @@ -194,6 +216,8 @@ void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx) set_bit(idx * ndev->bits_per_vector, &mask); writew(mask, ndev->reg_ofs.ldb_mask); + tasklet_disable(&ndev->db_cb[idx].irq_work); + ndev->db_cb[idx].callback = NULL; } @@ -955,12 +979,16 @@ static irqreturn_t bwd_callback_msix_irq(int irq, void *data) { struct ntb_db_cb *db_cb = data; struct ntb_device *ndev = db_cb->ndev; + unsigned long mask; dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq, db_cb->db_num); - if (db_cb->callback) - db_cb->callback(db_cb->data, db_cb->db_num); + mask = readw(ndev->reg_ofs.ldb_mask); + set_bit(db_cb->db_num * ndev->bits_per_vector, &mask); + writew(mask, ndev->reg_ofs.ldb_mask); + + tasklet_schedule(&db_cb->irq_work); /* No need to check for the specific HB irq, any interrupt means * we're connected. @@ -976,12 +1004,16 @@ static irqreturn_t xeon_callback_msix_irq(int irq, void *data) { struct ntb_db_cb *db_cb = data; struct ntb_device *ndev = db_cb->ndev; + unsigned long mask; dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq, db_cb->db_num); - if (db_cb->callback) - db_cb->callback(db_cb->data, db_cb->db_num); + mask = readw(ndev->reg_ofs.ldb_mask); + set_bit(db_cb->db_num * ndev->bits_per_vector, &mask); + writew(mask, ndev->reg_ofs.ldb_mask); + + tasklet_schedule(&db_cb->irq_work); /* On Sandybridge, there are 16 bits in the interrupt register * but only 4 vectors. So, 5 bits are assigned to the first 3 -- cgit v1.1