lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Date:	Sun, 7 Sep 2014 23:19:58 -0400
From:	Jon Mason <jdmason@...zu.us>
To:	Dave Jiang <dave.jiang@...el.com>
Cc:	linux-kernel@...r.kernel.org
Subject: Re: [PATCH 6/6] ntb: workaround for high traffic hardware hang

On Thu, Aug 28, 2014 at 01:53:29PM -0700, Dave Jiang wrote:
> A hardware errata causes the NTB to hang when heavy bi-directional traffic
> in addition to the usage of BAR0/1 (where the registers reside, including
> the doorbell registers to trigger interrupts).
> 
> This workaround is only available on Haswell platform.
> The workaround is to enable split BAR in the BIOS to allow the 64bit BAR4 to
> be split into two 32bit BAR4 and BAR5. The BAR4 shall be pointed to LAPIC
> region of the remote host. We will bypass the doorbell mechanism and directly
> trigger the MSIX interrupts. The offsets and vectors are exchanged during
> transport scratch pad negotiation. The scratch pads are now overloaded
> in order to allow the exchange of the information. This gets around using
> the doorbell and prevents the lockup with additional pcode changes in BIOS.

I REALLY don't like a driver mucking with the MSI-X table to work
around hardware issues.  I don't see any presidence for this kind of
behavior in other drivers.  Also, this patch is fairly invasive.  I
realize that there isn't much alternative, other than polling.  In
fact, I think I'd rather see polling.

Thanks,
Jon

> 
> Signed-off-by: Dave Jiang <dave.jiang@...el.com>
> ---
>  drivers/ntb/ntb_hw.c        |  177 +++++++++++++++++++++++++++++++++++++------
>  drivers/ntb/ntb_hw.h        |    9 ++
>  drivers/ntb/ntb_regs.h      |    1 
>  drivers/ntb/ntb_transport.c |  126 ++++++++++++++++++-------------
>  4 files changed, 237 insertions(+), 76 deletions(-)
> 
> diff --git a/drivers/ntb/ntb_hw.c b/drivers/ntb/ntb_hw.c
> index cef9d8a..97e18c3 100644
> --- a/drivers/ntb/ntb_hw.c
> +++ b/drivers/ntb/ntb_hw.c
> @@ -53,6 +53,8 @@
>  #include <linux/pci.h>
>  #include <linux/random.h>
>  #include <linux/slab.h>
> +#include <linux/msi.h>
> +#include <linux/interrupt.h>
>  #include "ntb_hw.h"
>  #include "ntb_regs.h"
>  
> @@ -150,17 +152,19 @@ static void ntb_set_errata_flags(struct ntb_device *ndev)
>  	case PCI_DEVICE_ID_INTEL_NTB_SS_JSF:
>  	case PCI_DEVICE_ID_INTEL_NTB_SS_SNB:
>  	case PCI_DEVICE_ID_INTEL_NTB_SS_IVT:
> -	case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
>  	case PCI_DEVICE_ID_INTEL_NTB_PS_JSF:
>  	case PCI_DEVICE_ID_INTEL_NTB_PS_SNB:
>  	case PCI_DEVICE_ID_INTEL_NTB_PS_IVT:
> -	case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
>  	case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF:
>  	case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB:
>  	case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT:
> -	case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
>  		ndev->wa_flags |= WA_SNB_ERR;
>  		break;
> +	case PCI_DEVICE_ID_INTEL_NTB_SS_HSX:
> +	case PCI_DEVICE_ID_INTEL_NTB_PS_HSX:
> +	case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX:
> +		ndev->wa_flags |= WA_HSX_ERR;
> +		break;
>  	}
>  }
>  
> @@ -209,9 +213,13 @@ static void ntb_irq_work(unsigned long data)
>  		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);
> +		if (ndev->wa_flags & WA_HSX_ERR)
> +			enable_irq(db_cb->irq);
> +		else {
> +			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);
> +		}
>  	}
>  }
>  
> @@ -246,9 +254,12 @@ int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx,
>  		     (unsigned long) &ndev->db_cb[idx]);
>  
>  	/* unmask interrupt */
> -	mask = readw(ndev->reg_ofs.ldb_mask);
> -	clear_bit(idx * ndev->bits_per_vector, &mask);
> -	writew(mask, ndev->reg_ofs.ldb_mask);
> +	if (!(ndev->wa_flags & WA_HSX_ERR)) {
> +		/* unmask interrupt */
> +		mask = readw(ndev->reg_ofs.ldb_mask);
> +		clear_bit(idx * ndev->bits_per_vector, &mask);
> +		writew(mask, ndev->reg_ofs.ldb_mask);
> +	}
>  
>  	return 0;
>  }
> @@ -268,9 +279,11 @@ void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx)
>  	if (idx >= ndev->max_cbs || !ndev->db_cb[idx].callback)
>  		return;
>  
> -	mask = readw(ndev->reg_ofs.ldb_mask);
> -	set_bit(idx * ndev->bits_per_vector, &mask);
> -	writew(mask, ndev->reg_ofs.ldb_mask);
> +	if (!(ndev->wa_flags & WA_HSX_ERR)) {
> +		mask = readw(ndev->reg_ofs.ldb_mask);
> +		set_bit(idx * ndev->bits_per_vector, &mask);
> +		writew(mask, ndev->reg_ofs.ldb_mask);
> +	}
>  
>  	tasklet_disable(&ndev->db_cb[idx].irq_work);
>  
> @@ -518,6 +531,17 @@ void ntb_set_mw_addr(struct ntb_device *ndev, unsigned int mw, u64 addr)
>  	}
>  }
>  
> +static void ntb_generate_rirq(struct ntb_device *ndev, int vec)
> +{
> +	if (vec > 2) {
> +		dev_err(&ndev->pdev->dev, "%s: vec %d out of bounds\n",
> +			__func__, vec);
> +		return;
> +	}
> +
> +	writel(ndev->rirq[vec].data, ndev->mw[1].vbase + ndev->rirq[vec].ofs);
> +}
> +
>  /**
>   * ntb_ring_doorbell() - Set the doorbell on the secondary/external side
>   * @ndev: pointer to ntb_device instance
> @@ -532,7 +556,9 @@ void ntb_ring_doorbell(struct ntb_device *ndev, unsigned int db)
>  {
>  	dev_dbg(&ndev->pdev->dev, "%s: ringing doorbell %d\n", __func__, db);
>  
> -	if (ndev->hw_type == BWD_HW)
> +	if (ndev->wa_flags & WA_HSX_ERR)
> +		ntb_generate_rirq(ndev, db);
> +	else if (ndev->hw_type == BWD_HW)
>  		writeq((u64) 1 << db, ndev->reg_ofs.rdb);
>  	else
>  		writew(((1 << ndev->bits_per_vector) - 1) <<
> @@ -794,7 +820,26 @@ static int ntb_xeon_setup(struct ntb_device *ndev)
>  			 * the driver defaults, but write the Limit registers
>  			 * first just in case.
>  			 */
> -			if (ndev->split_bar)
> +			if (ndev->wa_flags & WA_HSX_ERR) {
> +				/* using BAR4, must be set to 1M */
> +				if (ndev->mw[1].bar_sz != 0x100000) {
> +					dev_err(&ndev->pdev->dev,
> +						"BAR4 must be 1M\n");
> +					return -EINVAL;
> +				}
> +
> +				/* set limit to 1M according to spec */
> +				writel(pci_resource_start(ndev->pdev, 1) + 0x100000,
> +				       ndev->reg_base + SNB_PBAR4LMT_OFFSET);
> +				/*
> +				 * need to point SBAR4XLAT to remote
> +				 * interrupt region
> +				 */
> +				writel(0xfee00000,
> +				       ndev->reg_base + SNB_SBAR4XLAT_OFFSET);
> +
> +				ndev->limits.max_mw = HSX_ERRATA_MAX_MW;
> +			} else if (ndev->split_bar)
>  				ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW;
>  			else
>  				ndev->limits.max_mw = SNB_MAX_MW;
> @@ -911,7 +956,22 @@ static int ntb_xeon_setup(struct ntb_device *ndev)
>  		if (ndev->split_bar) {
>  			ndev->reg_ofs.bar5_xlat =
>  				ndev->reg_base + SNB_SBAR5XLAT_OFFSET;
> -			ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW;
> +
> +			if (ndev->wa_flags & WA_HSX_ERR) {
> +				/* using BAR4, must be set to 1M */
> +				if (ndev->mw[1].bar_sz != 0x100000) {
> +					dev_err(&ndev->pdev->dev,
> +						"BAR4 must be 1M\n");
> +					return -EINVAL;
> +				}
> +
> +				/* set limit to 1M according to spec */
> +				writel(pci_resource_start(ndev->pdev, 1) + 0x100000,
> +				       ndev->reg_base + SNB_PBAR4LMT_OFFSET);
> +				writel(0xfee00000, ndev->reg_ofs.bar4_xlat);
> +				ndev->limits.max_mw = HSX_ERRATA_MAX_MW;
> +			} else
> +				ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW;
>  		} else
>  			ndev->limits.max_mw = SNB_MAX_MW;
>  		break;
> @@ -943,7 +1003,22 @@ static int ntb_xeon_setup(struct ntb_device *ndev)
>  		if (ndev->split_bar) {
>  			ndev->reg_ofs.bar5_xlat =
>  				ndev->reg_base + SNB_PBAR5XLAT_OFFSET;
> -			ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW;
> +
> +			if (ndev->wa_flags & WA_HSX_ERR) {
> +				/* using BAR4, must be set to 1M */
> +				if (ndev->mw[1].bar_sz != 0x100000) {
> +					dev_err(&ndev->pdev->dev,
> +						"BAR4 must be 1M\n");
> +					return -EINVAL;
> +				}
> +
> +				/* set limit to 1M according to spec */
> +				writel(pci_resource_start(ndev->pdev, 1) + 0x100000,
> +				       ndev->reg_base + SNB_PBAR4LMT_OFFSET);
> +				writel(0xfee00000, ndev->reg_ofs.bar4_xlat);
> +				ndev->limits.max_mw = HSX_ERRATA_MAX_MW;
> +			} else
> +				ndev->limits.max_mw = HSX_SPLITBAR_MAX_MW;
>  		} else
>  			ndev->limits.max_mw = SNB_MAX_MW;
>  		break;
> @@ -1085,9 +1160,14 @@ static irqreturn_t xeon_callback_msix_irq(int irq, void *data)
>  	dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq,
>  		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);
> +	if (ndev->wa_flags & WA_HSX_ERR) {
> +		disable_irq_nosync(irq);
> +		db_cb->irq = irq;
> +	} else {
> +		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);
>  
> @@ -1096,8 +1176,11 @@ static irqreturn_t xeon_callback_msix_irq(int irq, void *data)
>  	 * vectors, with the 4th having a single bit for link
>  	 * interrupts.
>  	 */
> -	writew(((1 << ndev->bits_per_vector) - 1) <<
> -	       (db_cb->db_num * ndev->bits_per_vector), ndev->reg_ofs.ldb);
> +	if (!(ndev->wa_flags & WA_HSX_ERR)) {
> +		writew(((1 << ndev->bits_per_vector) - 1) <<
> +			(db_cb->db_num * ndev->bits_per_vector),
> +			ndev->reg_ofs.ldb);
> +	}
>  
>  	return IRQ_HANDLED;
>  }
> @@ -1160,6 +1243,9 @@ static int ntb_setup_snb_msix(struct ntb_device *ndev, int msix_entries)
>  	struct pci_dev *pdev = ndev->pdev;
>  	struct msix_entry *msix;
>  	int rc, i;
> +	struct msi_desc *entry;
> +	u32 laddr = 0;
> +	u32 data = 0;
>  
>  	if (msix_entries < ndev->limits.msix_cnt)
>  		return -ENOSPC;
> @@ -1191,6 +1277,31 @@ static int ntb_setup_snb_msix(struct ntb_device *ndev, int msix_entries)
>  	ndev->num_msix = msix_entries;
>  	ndev->max_cbs = msix_entries - 1;
>  
> +	if (ndev->wa_flags & WA_HSX_ERR) {
> +		i = 0;
> +
> +		/*
> +		 * acquire the interrupt region in the LAPIC for the
> +		 * MSIX vectors
> +		 */
> +		list_for_each_entry(entry, &pdev->msi_list, list) {
> +			unsigned int offset = ndev->msix_entries[i].entry *
> +				PCI_MSIX_ENTRY_SIZE;
> +
> +			laddr = readl(entry->mask_base + offset +
> +					PCI_MSIX_ENTRY_LOWER_ADDR);
> +			dev_dbg(&pdev->dev, "local lower MSIX addr(%d): %#x\n",
> +				i, laddr);
> +			ndev->lirq[i].ofs = 0x1fffff & laddr;
> +			data = readl(entry->mask_base + offset +
> +					PCI_MSIX_ENTRY_DATA);
> +			dev_dbg(&pdev->dev, "local MSIX data(%d): %#x\n",
> +				i, data);
> +			ndev->lirq[i].data = data;
> +			i++;
> +		}
> +	}
> +
>  	return 0;
>  
>  err:
> @@ -1288,6 +1399,11 @@ static int ntb_setup_msi(struct ntb_device *ndev)
>  	struct pci_dev *pdev = ndev->pdev;
>  	int rc;
>  
> +	if (ndev->wa_flags & WA_HSX_ERR) {
> +		dev_err(&pdev->dev, "Platform errata does not support MSI\n");
> +		return -EINVAL;
> +	}
> +
>  	rc = pci_enable_msi(pdev);
>  	if (rc)
>  		return rc;
> @@ -1307,6 +1423,11 @@ static int ntb_setup_intx(struct ntb_device *ndev)
>  	struct pci_dev *pdev = ndev->pdev;
>  	int rc;
>  
> +	if (ndev->wa_flags & WA_HSX_ERR) {
> +		dev_err(&pdev->dev, "Platform errata does not support INTX\n");
> +		return -EINVAL;
> +	}
> +
>  	pci_msi_off(pdev);
>  
>  	/* Verify intx is enabled */
> @@ -1720,6 +1841,17 @@ static int ntb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
>  	if (rc)
>  		goto err;
>  
> +	if (!ndev->split_bar && (ndev->wa_flags & WA_HSX_ERR)) {
> +		dev_warn(&pdev->dev,
> +			 "Please config NTB split BAR for errata workaround\n");
> +		return -EINVAL;
> +	}
> +
> +	/*
> +	 * From this point on we will assume that split BAR is set when
> +	 * WA_HSX_ERR is set
> +	 */
> +
>  	ndev->mw = kcalloc(sizeof(struct ntb_mw), ndev->limits.max_mw,
>  			   GFP_KERNEL);
>  	if (!ndev->mw) {
> @@ -1751,8 +1883,7 @@ static int ntb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
>  		 * with the errata we need to steal last of the memory
>  		 * windows for workarounds and they point to MMIO registers.
>  		 */
> -		if ((ndev->wa_flags & WA_SNB_ERR) &&
> -		    (i == (ndev->limits.max_mw - 1))) {
> +		if ((ndev->wa_flags & (WA_SNB_ERR | WA_HSX_ERR)) && (i > 0)) {
>  			ndev->mw[i].vbase =
>  				ioremap_nocache(pci_resource_start(pdev,
>  							MW_TO_BAR(i)),
> diff --git a/drivers/ntb/ntb_hw.h b/drivers/ntb/ntb_hw.h
> index 96de5fc..d59650e 100644
> --- a/drivers/ntb/ntb_hw.h
> +++ b/drivers/ntb/ntb_hw.h
> @@ -109,9 +109,16 @@ struct ntb_db_cb {
>  	void *data;
>  	struct ntb_device *ndev;
>  	struct tasklet_struct irq_work;
> +	unsigned int irq;
> +};
> +
> +struct msix_info {
> +	u32 ofs;
> +	u32 data;
>  };
>  
>  #define WA_SNB_ERR	0x00000001
> +#define WA_HSX_ERR	0x00000002
>  
>  struct ntb_device {
>  	struct pci_dev *pdev;
> @@ -161,6 +168,8 @@ struct ntb_device {
>  	struct dentry *debugfs_info;
>  
>  	unsigned int wa_flags;
> +	struct msix_info lirq[4];
> +	struct msix_info rirq[4];
>  };
>  
>  /**
> diff --git a/drivers/ntb/ntb_regs.h b/drivers/ntb/ntb_regs.h
> index f028ff8..7eb1440 100644
> --- a/drivers/ntb/ntb_regs.h
> +++ b/drivers/ntb/ntb_regs.h
> @@ -60,6 +60,7 @@
>  #define HSX_SPLITBAR_MAX_MW	3
>  #define SNB_MAX_MW		2
>  #define SNB_ERRATA_MAX_MW	1
> +#define HSX_ERRATA_MAX_MW	1
>  
>  #define SNB_DB_HW_LINK		0x8000
>  
> diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c
> index 24f0ac1..7ab4d63 100644
> --- a/drivers/ntb/ntb_transport.c
> +++ b/drivers/ntb/ntb_transport.c
> @@ -56,6 +56,7 @@
>  #include <linux/pci.h>
>  #include <linux/slab.h>
>  #include <linux/types.h>
> +#include <linux/sched.h>
>  #include "ntb_hw.h"
>  
>  #define NTB_TRANSPORT_VERSION	3
> @@ -188,15 +189,24 @@ struct ntb_payload_header {
>  	unsigned int flags;
>  };
>  
> +/*
> + * Using 7 scratch pads, 1 left
> + * VERSION
> + * QP_LINKS
> + * NUM_QPS NUM_MWS
> + * MW0_SZ MW1_SZ MW2_SZ MW3_SZ
> + * DATA0 MSIX_OFS0
> + * DATA1 MSIX_OFS1
> + * DATA2 MSIX_OFS2
> + */
>  enum {
>  	VERSION = 0,
>  	QP_LINKS,
> -	NUM_QPS,
>  	NUM_MWS,
> -	MW0_SZ_HIGH,
> -	MW0_SZ_LOW,
> -	MW1_SZ_HIGH,
> -	MW1_SZ_LOW,
> +	MW_SZ,
> +	MSIX_OFS0,
> +	MSIX_OFS1,
> +	MSIX_OFS2,
>  	MAX_SPAD,
>  };
>  
> @@ -687,37 +697,45 @@ static void ntb_transport_link_work(struct work_struct *work)
>  	int rc, i;
>  
>  	/* send the local info, in the opposite order of the way we read it */
> -	for (i = 0; i < ntb_max_mw(ndev); i++) {
> -		rc = ntb_write_remote_spad(ndev, MW0_SZ_HIGH + (i * 2),
> -					   ntb_get_mw_size(ndev, i) >> 32);
> -		if (rc) {
> -			dev_err(&pdev->dev, "Error writing %u to remote spad %d\n",
> -				(u32)(ntb_get_mw_size(ndev, i) >> 32),
> -				MW0_SZ_HIGH + (i * 2));
> -			goto out;
> -		}
>  
> -		rc = ntb_write_remote_spad(ndev, MW0_SZ_LOW + (i * 2),
> -					   (u32) ntb_get_mw_size(ndev, i));
> +	for (i = 0; i < 3; i++) {
> +		val = (ndev->lirq[i].ofs & 0x1fffff) |
> +		      (ndev->lirq[i].data & 0xff) << 24;
> +
> +		rc = ntb_write_remote_spad(ndev, MSIX_OFS0 + i, val);
>  		if (rc) {
> -			dev_err(&pdev->dev, "Error writing %u to remote spad %d\n",
> -				(u32) ntb_get_mw_size(ndev, i),
> -				MW0_SZ_LOW + (i * 2));
> +			dev_err(&pdev->dev, "Error writing %x to remote spad %d\n",
> +				val, MSIX_OFS0 + i);
>  			goto out;
>  		}
>  	}
>  
> -	rc = ntb_write_remote_spad(ndev, NUM_MWS, ntb_max_mw(ndev));
> +	if (ntb_max_mw(ndev) > 4) {
> +		dev_err(&pdev->dev,
> +			"Greater than 4 memory window unsupported!\n");
> +		goto out;
> +	}
> +
> +	val = 0;
> +	for (i = 0; i < ntb_max_mw(ndev); i++) {
> +		u32 size;
> +
> +		size = ilog2(rounddown_pow_of_two(ntb_get_mw_size(ndev, i)));
> +		val |= (size & 0xff) << (8 * i);
> +	}
> +
> +	rc = ntb_write_remote_spad(ndev, MW_SZ, val);
>  	if (rc) {
> -		dev_err(&pdev->dev, "Error writing %x to remote spad %d\n",
> -			ntb_max_mw(ndev), NUM_MWS);
> +		dev_err(&pdev->dev, "Error writing %#x to remote spad %d\n",
> +			val, MW_SZ);
>  		goto out;
>  	}
>  
> -	rc = ntb_write_remote_spad(ndev, NUM_QPS, nt->max_qps);
> +	val = (ntb_max_mw(ndev) & 0xffff) | (nt->max_qps & 0xffff) << 16;
> +	rc = ntb_write_remote_spad(ndev, NUM_MWS, val);
>  	if (rc) {
> -		dev_err(&pdev->dev, "Error writing %x to remote spad %d\n",
> -			nt->max_qps, NUM_QPS);
> +		dev_err(&pdev->dev, "Error writing %#x to remote spad %d\n",
> +			val, NUM_MWS);
>  		goto out;
>  	}
>  
> @@ -739,46 +757,31 @@ static void ntb_transport_link_work(struct work_struct *work)
>  		goto out;
>  	dev_dbg(&pdev->dev, "Remote version = %d\n", val);
>  
> -	rc = ntb_read_remote_spad(ndev, NUM_QPS, &val);
> -	if (rc) {
> -		dev_err(&pdev->dev, "Error reading remote spad %d\n", NUM_QPS);
> -		goto out;
> -	}
> -
> -	if (val != nt->max_qps)
> -		goto out;
> -	dev_dbg(&pdev->dev, "Remote max number of qps = %d\n", val);
> -
>  	rc = ntb_read_remote_spad(ndev, NUM_MWS, &val);
>  	if (rc) {
>  		dev_err(&pdev->dev, "Error reading remote spad %d\n", NUM_MWS);
>  		goto out;
>  	}
>  
> -	if (val != ntb_max_mw(ndev))
> +	if (((val >> 16) & 0xffff) != nt->max_qps)
>  		goto out;
> -	dev_dbg(&pdev->dev, "Remote number of mws = %d\n", val);
>  
> -	for (i = 0; i < ntb_max_mw(ndev); i++) {
> -		u64 val64;
> +	dev_dbg(&pdev->dev, "Remote max number of qps = %d\n",
> +		(val >> 16) & 0xffff);
>  
> -		rc = ntb_read_remote_spad(ndev, MW0_SZ_HIGH + (i * 2), &val);
> -		if (rc) {
> -			dev_err(&pdev->dev, "Error reading remote spad %d\n",
> -				MW0_SZ_HIGH + (i * 2));
> -			goto out1;
> -		}
> +	if ((val & 0xffff) != ntb_max_mw(ndev))
> +		goto out;
>  
> -		val64 = (u64) val << 32;
> +	dev_dbg(&pdev->dev, "Remote number of mws = %d\n", val & 0xffff);
>  
> -		rc = ntb_read_remote_spad(ndev, MW0_SZ_LOW + (i * 2), &val);
> -		if (rc) {
> -			dev_err(&pdev->dev, "Error reading remote spad %d\n",
> -				MW0_SZ_LOW + (i * 2));
> -			goto out1;
> -		}
> +	rc = ntb_read_remote_spad(ndev, MW_SZ, &val);
> +	if (rc) {
> +		dev_err(&pdev->dev, "Error reading remote spad %d\n", MW_SZ);
> +		goto out1;
> +	}
>  
> -		val64 |= val;
> +	for (i = 0; i < ntb_max_mw(ndev); i++) {
> +		u64 val64 = 1 << ((val >> (i * 8)) & 0xff);
>  
>  		dev_dbg(&pdev->dev, "Remote MW%d size = %llu\n", i, val64);
>  
> @@ -787,6 +790,23 @@ static void ntb_transport_link_work(struct work_struct *work)
>  			goto out1;
>  	}
>  
> +	for (i = 0; i < 3; i++) {
> +		rc = ntb_read_remote_spad(ndev, MSIX_OFS0 + i, &val);
> +		if (rc) {
> +			dev_err(&pdev->dev,
> +				"Error reading remote spad %d\n",
> +				MSIX_OFS0 + i);
> +			goto out;
> +		}
> +
> +		ndev->rirq[i].ofs = 0x1ffff & val;
> +		ndev->rirq[i].data = (val >> 24) & 0xff;
> +		dev_dbg(&pdev->dev, "received MSIX_OFS%d: %#x\n",
> +			i, ndev->rirq[i].ofs);
> +		dev_dbg(&pdev->dev, "received MSIX_DATA%d: %#x\n",
> +			i, ndev->rirq[i].data);
> +	}
> +
>  	nt->transport_link = NTB_LINK_UP;
>  
>  	for (i = 0; i < nt->max_qps; i++) {
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists