Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 07f5fef9 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'ntb-3.15' of git://github.com/jonmason/ntb

Pull PCIe non-transparent bridge fixes and features from Jon Mason:
 "NTB driver bug fixes to address issues in list traversal, skb leak in
  ntb_netdev, a typo, and a leak of msix entries in the error path.
  Clean ups of the event handling logic, as well as a overall style
  cleanup.  Finally, the driver was converted to use the new
  pci_enable_msix_range logic (and the refactoring to go along with it)"

* tag 'ntb-3.15' of git://github.com/jonmason/ntb:
  ntb: Use pci_enable_msix_range() instead of pci_enable_msix()
  ntb: Split ntb_setup_msix() into separate BWD/SNB routines
  ntb: Use pci_msix_vec_count() to obtain number of MSI-Xs
  NTB: Code Style Clean-up
  NTB: client event cleanup
  ntb: Fix leakage of ntb_device::msix_entries[] array
  NTB: Fix typo in setting one translation register
  ntb_netdev: Fix skb free issue in open
  ntb_netdev: Fix list_for_each_entry exit issue
parents 96c57ade f220baad
Loading
Loading
Loading
Loading
+20 −7
Original line number Original line Diff line number Diff line
@@ -78,11 +78,19 @@ static void ntb_netdev_event_handler(void *data, int status)
	netdev_dbg(ndev, "Event %x, Link %x\n", status,
	netdev_dbg(ndev, "Event %x, Link %x\n", status,
		   ntb_transport_link_query(dev->qp));
		   ntb_transport_link_query(dev->qp));


	/* Currently, only link status event is supported */
	switch (status) {
	if (status)
	case NTB_LINK_DOWN:
		netif_carrier_on(ndev);
	else
		netif_carrier_off(ndev);
		netif_carrier_off(ndev);
		break;
	case NTB_LINK_UP:
		if (!ntb_transport_link_query(dev->qp))
			return;

		netif_carrier_on(ndev);
		break;
	default:
		netdev_warn(ndev, "Unsupported event type %d\n", status);
	}
}
}


static void ntb_netdev_rx_handler(struct ntb_transport_qp *qp, void *qp_data,
static void ntb_netdev_rx_handler(struct ntb_transport_qp *qp, void *qp_data,
@@ -182,9 +190,11 @@ static int ntb_netdev_open(struct net_device *ndev)


		rc = ntb_transport_rx_enqueue(dev->qp, skb, skb->data,
		rc = ntb_transport_rx_enqueue(dev->qp, skb, skb->data,
					      ndev->mtu + ETH_HLEN);
					      ndev->mtu + ETH_HLEN);
		if (rc == -EINVAL)
		if (rc == -EINVAL) {
			dev_kfree_skb(skb);
			goto err;
			goto err;
		}
		}
	}


	netif_carrier_off(ndev);
	netif_carrier_off(ndev);
	ntb_transport_link_up(dev->qp);
	ntb_transport_link_up(dev->qp);
@@ -367,12 +377,15 @@ static void ntb_netdev_remove(struct pci_dev *pdev)
{
{
	struct net_device *ndev;
	struct net_device *ndev;
	struct ntb_netdev *dev;
	struct ntb_netdev *dev;
	bool found = false;


	list_for_each_entry(dev, &dev_list, list) {
	list_for_each_entry(dev, &dev_list, list) {
		if (dev->pdev == pdev)
		if (dev->pdev == pdev) {
			found = true;
			break;
			break;
		}
		}
	if (dev == NULL)
	}
	if (!found)
		return;
		return;


	list_del(&dev->list);
	list_del(&dev->list);
+107 −85
Original line number Original line Diff line number Diff line
@@ -91,7 +91,7 @@ static struct dentry *debugfs_dir;
/* Translate memory window 0,1 to BAR 2,4 */
/* Translate memory window 0,1 to BAR 2,4 */
#define MW_TO_BAR(mw)	(mw * NTB_MAX_NUM_MW + 2)
#define MW_TO_BAR(mw)	(mw * NTB_MAX_NUM_MW + 2)


static DEFINE_PCI_DEVICE_TABLE(ntb_pci_tbl) = {
static const struct pci_device_id ntb_pci_tbl[] = {
	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_BWD)},
	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_BWD)},
	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_JSF)},
	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_JSF)},
	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_SNB)},
	{PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_SNB)},
@@ -120,7 +120,8 @@ MODULE_DEVICE_TABLE(pci, ntb_pci_tbl);
 * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
 * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
 */
 */
int ntb_register_event_callback(struct ntb_device *ndev,
int ntb_register_event_callback(struct ntb_device *ndev,
			    void (*func)(void *handle, enum ntb_hw_event event))
				void (*func)(void *handle,
					     enum ntb_hw_event event))
{
{
	if (ndev->event_cb)
	if (ndev->event_cb)
		return -EINVAL;
		return -EINVAL;
@@ -715,9 +716,9 @@ static int ntb_xeon_setup(struct ntb_device *ndev)
			       SNB_PBAR4LMT_OFFSET);
			       SNB_PBAR4LMT_OFFSET);
			/* HW errata on the Limit registers.  They can only be
			/* HW errata on the Limit registers.  They can only be
			 * written when the base register is 4GB aligned and
			 * written when the base register is 4GB aligned and
			 * < 32bit.  This should already be the case based on the
			 * < 32bit.  This should already be the case based on
			 * driver defaults, but write the Limit registers first
			 * the driver defaults, but write the Limit registers
			 * just in case.
			 * first just in case.
			 */
			 */
		} else {
		} else {
			ndev->limits.max_mw = SNB_MAX_MW;
			ndev->limits.max_mw = SNB_MAX_MW;
@@ -739,9 +740,9 @@ static int ntb_xeon_setup(struct ntb_device *ndev)
			writeq(0, ndev->reg_base + SNB_PBAR4LMT_OFFSET);
			writeq(0, ndev->reg_base + SNB_PBAR4LMT_OFFSET);
			/* HW errata on the Limit registers.  They can only be
			/* HW errata on the Limit registers.  They can only be
			 * written when the base register is 4GB aligned and
			 * written when the base register is 4GB aligned and
			 * < 32bit.  This should already be the case based on the
			 * < 32bit.  This should already be the case based on
			 * driver defaults, but write the Limit registers first
			 * the driver defaults, but write the Limit registers
			 * just in case.
			 * first just in case.
			 */
			 */
		}
		}


@@ -785,7 +786,7 @@ static int ntb_xeon_setup(struct ntb_device *ndev)
				/* B2B_XLAT_OFFSET is a 64bit register, but can
				/* B2B_XLAT_OFFSET is a 64bit register, but can
				 * only take 32bit writes
				 * only take 32bit writes
				 */
				 */
				writel(SNB_MBAR01_DSD_ADDR & 0xffffffff,
				writel(SNB_MBAR01_USD_ADDR & 0xffffffff,
				       ndev->reg_base + SNB_B2B_XLAT_OFFSETL);
				       ndev->reg_base + SNB_B2B_XLAT_OFFSETL);
				writel(SNB_MBAR01_USD_ADDR >> 32,
				writel(SNB_MBAR01_USD_ADDR >> 32,
				       ndev->reg_base + SNB_B2B_XLAT_OFFSETU);
				       ndev->reg_base + SNB_B2B_XLAT_OFFSETU);
@@ -1079,111 +1080,131 @@ static irqreturn_t ntb_interrupt(int irq, void *dev)
	return IRQ_HANDLED;
	return IRQ_HANDLED;
}
}


static int ntb_setup_msix(struct ntb_device *ndev)
static int ntb_setup_snb_msix(struct ntb_device *ndev, int msix_entries)
{
{
	struct pci_dev *pdev = ndev->pdev;
	struct pci_dev *pdev = ndev->pdev;
	struct msix_entry *msix;
	struct msix_entry *msix;
	int msix_entries;
	int rc, i;
	int rc, i;
	u16 val;

	if (!pdev->msix_cap) {
		rc = -EIO;
		goto err;
	}

	rc = pci_read_config_word(pdev, pdev->msix_cap + PCI_MSIX_FLAGS, &val);
	if (rc)
		goto err;


	msix_entries = msix_table_size(val);
	if (msix_entries < ndev->limits.msix_cnt)
	if (msix_entries > ndev->limits.msix_cnt) {
		return -ENOSPC;
		rc = -EINVAL;
		goto err;
	}


	ndev->msix_entries = kmalloc(sizeof(struct msix_entry) * msix_entries,
	rc = pci_enable_msix_exact(pdev, ndev->msix_entries, msix_entries);
				     GFP_KERNEL);
	if (!ndev->msix_entries) {
		rc = -ENOMEM;
		goto err;
	}

	for (i = 0; i < msix_entries; i++)
		ndev->msix_entries[i].entry = i;

	rc = pci_enable_msix(pdev, ndev->msix_entries, msix_entries);
	if (rc < 0)
	if (rc < 0)
		goto err1;
		return rc;
	if (rc > 0) {
		/* On SNB, the link interrupt is always tied to 4th vector.  If
		 * we can't get all 4, then we can't use MSI-X.
		 */
		if (ndev->hw_type != BWD_HW) {
			rc = -EIO;
			goto err1;
		}

		dev_warn(&pdev->dev,
			 "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++) {
	for (i = 0; i < msix_entries; i++) {
		msix = &ndev->msix_entries[i];
		msix = &ndev->msix_entries[i];
		WARN_ON(!msix->vector);
		WARN_ON(!msix->vector);


		/* Use the last MSI-X vector for Link status */
		if (ndev->hw_type == BWD_HW) {
			rc = request_irq(msix->vector, bwd_callback_msix_irq, 0,
					 "ntb-callback-msix", &ndev->db_cb[i]);
			if (rc)
				goto err2;
		} else {
		if (i == msix_entries - 1) {
		if (i == msix_entries - 1) {
			rc = request_irq(msix->vector,
			rc = request_irq(msix->vector,
					 xeon_event_msix_irq, 0,
					 xeon_event_msix_irq, 0,
					 "ntb-event-msix", ndev);
					 "ntb-event-msix", ndev);
			if (rc)
			if (rc)
					goto err2;
				goto err;
		} else {
		} else {
			rc = request_irq(msix->vector,
			rc = request_irq(msix->vector,
					 xeon_callback_msix_irq, 0,
					 xeon_callback_msix_irq, 0,
					 "ntb-callback-msix",
					 "ntb-callback-msix",
					 &ndev->db_cb[i]);
					 &ndev->db_cb[i]);
			if (rc)
			if (rc)
					goto err2;
				goto err;
			}
		}
		}
	}
	}


	ndev->num_msix = msix_entries;
	ndev->num_msix = msix_entries;
	if (ndev->hw_type == BWD_HW)
		ndev->max_cbs = msix_entries;
	else
	ndev->max_cbs = msix_entries - 1;
	ndev->max_cbs = msix_entries - 1;


	return 0;
	return 0;


err2:
err:
	while (--i >= 0) {
	while (--i >= 0) {
		/* Code never reaches here for entry nr 'ndev->num_msix - 1' */
		msix = &ndev->msix_entries[i];
		msix = &ndev->msix_entries[i];
		if (ndev->hw_type != BWD_HW && i == ndev->num_msix - 1)
			free_irq(msix->vector, ndev);
		else
		free_irq(msix->vector, &ndev->db_cb[i]);
		free_irq(msix->vector, &ndev->db_cb[i]);
	}
	}

	pci_disable_msix(pdev);
	pci_disable_msix(pdev);
	ndev->num_msix = 0;

	return rc;
}

static int ntb_setup_bwd_msix(struct ntb_device *ndev, int msix_entries)
{
	struct pci_dev *pdev = ndev->pdev;
	struct msix_entry *msix;
	int rc, i;

	msix_entries = pci_enable_msix_range(pdev, ndev->msix_entries,
					     1, msix_entries);
	if (msix_entries < 0)
		return msix_entries;

	for (i = 0; i < msix_entries; i++) {
		msix = &ndev->msix_entries[i];
		WARN_ON(!msix->vector);

		rc = request_irq(msix->vector, bwd_callback_msix_irq, 0,
				 "ntb-callback-msix", &ndev->db_cb[i]);
		if (rc)
			goto err;
	}

	ndev->num_msix = msix_entries;
	ndev->max_cbs = msix_entries;

	return 0;

err:
	while (--i >= 0)
		free_irq(msix->vector, &ndev->db_cb[i]);

	pci_disable_msix(pdev);
	ndev->num_msix = 0;

	return rc;
}

static int ntb_setup_msix(struct ntb_device *ndev)
{
	struct pci_dev *pdev = ndev->pdev;
	int msix_entries;
	int rc, i;

	msix_entries = pci_msix_vec_count(pdev);
	if (msix_entries < 0) {
		rc = msix_entries;
		goto err;
	} else if (msix_entries > ndev->limits.msix_cnt) {
		rc = -EINVAL;
		goto err;
	}

	ndev->msix_entries = kmalloc(sizeof(struct msix_entry) * msix_entries,
				     GFP_KERNEL);
	if (!ndev->msix_entries) {
		rc = -ENOMEM;
		goto err;
	}

	for (i = 0; i < msix_entries; i++)
		ndev->msix_entries[i].entry = i;

	if (ndev->hw_type == BWD_HW)
		rc = ntb_setup_bwd_msix(ndev, msix_entries);
	else
		rc = ntb_setup_snb_msix(ndev, msix_entries);
	if (rc)
		goto err1;

	return 0;

err1:
err1:
	kfree(ndev->msix_entries);
	kfree(ndev->msix_entries);
	dev_err(&pdev->dev, "Error allocating MSI-X interrupt\n");
err:
err:
	ndev->num_msix = 0;
	dev_err(&pdev->dev, "Error allocating MSI-X interrupt\n");
	return rc;
	return rc;
}
}


@@ -1281,6 +1302,7 @@ static void ntb_free_interrupts(struct ntb_device *ndev)
				free_irq(msix->vector, &ndev->db_cb[i]);
				free_irq(msix->vector, &ndev->db_cb[i]);
		}
		}
		pci_disable_msix(pdev);
		pci_disable_msix(pdev);
		kfree(ndev->msix_entries);
	} else {
	} else {
		free_irq(pdev->irq, ndev);
		free_irq(pdev->irq, ndev);


+2 −6
Original line number Original line Diff line number Diff line
@@ -45,6 +45,7 @@
 * Contact Information:
 * Contact Information:
 * Jon Mason <jon.mason@intel.com>
 * Jon Mason <jon.mason@intel.com>
 */
 */
#include <linux/ntb.h>


#define PCI_DEVICE_ID_INTEL_NTB_B2B_JSF		0x3725
#define PCI_DEVICE_ID_INTEL_NTB_B2B_JSF		0x3725
#define PCI_DEVICE_ID_INTEL_NTB_PS_JSF		0x3726
#define PCI_DEVICE_ID_INTEL_NTB_PS_JSF		0x3726
@@ -60,8 +61,6 @@
#define PCI_DEVICE_ID_INTEL_NTB_SS_HSX		0x2F0F
#define PCI_DEVICE_ID_INTEL_NTB_SS_HSX		0x2F0F
#define PCI_DEVICE_ID_INTEL_NTB_B2B_BWD		0x0C4E
#define PCI_DEVICE_ID_INTEL_NTB_B2B_BWD		0x0C4E


#define msix_table_size(control)	((control & PCI_MSIX_FLAGS_QSIZE)+1)

#ifndef readq
#ifndef readq
static inline u64 readq(void __iomem *addr)
static inline u64 readq(void __iomem *addr)
{
{
@@ -83,9 +82,6 @@ static inline void writeq(u64 val, void __iomem *addr)
#define NTB_BAR_MASK		((1 << NTB_BAR_MMIO) | (1 << NTB_BAR_23) |\
#define NTB_BAR_MASK		((1 << NTB_BAR_MMIO) | (1 << NTB_BAR_23) |\
				 (1 << NTB_BAR_45))
				 (1 << NTB_BAR_45))


#define NTB_LINK_DOWN		0
#define NTB_LINK_UP		1

#define NTB_HB_TIMEOUT		msecs_to_jiffies(1000)
#define NTB_HB_TIMEOUT		msecs_to_jiffies(1000)


#define NTB_MAX_NUM_MW		2
#define NTB_MAX_NUM_MW		2
+9 −11
Original line number Original line Diff line number Diff line
@@ -56,7 +56,6 @@
#include <linux/pci.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/types.h>
#include <linux/ntb.h>
#include "ntb_hw.h"
#include "ntb_hw.h"


#define NTB_TRANSPORT_VERSION	3
#define NTB_TRANSPORT_VERSION	3
@@ -1190,8 +1189,7 @@ static int ntb_process_rxc(struct ntb_transport_qp *qp)
	return 0;
	return 0;


err:
err:
	ntb_list_add(&qp->ntb_rx_pend_q_lock, &entry->entry,
	ntb_list_add(&qp->ntb_rx_pend_q_lock, &entry->entry, &qp->rx_pend_q);
		     &qp->rx_pend_q);
	/* Ensure that the data is fully copied out before clearing the flag */
	/* Ensure that the data is fully copied out before clearing the flag */
	wmb();
	wmb();
	hdr->flags = 0;
	hdr->flags = 0;
+12 −7
Original line number Original line Diff line number Diff line
@@ -54,6 +54,11 @@ struct ntb_client {
	void (*remove)(struct pci_dev *pdev);
	void (*remove)(struct pci_dev *pdev);
};
};


enum {
	NTB_LINK_DOWN = 0,
	NTB_LINK_UP,
};

int ntb_register_client(struct ntb_client *drvr);
int ntb_register_client(struct ntb_client *drvr);
void ntb_unregister_client(struct ntb_client *drvr);
void ntb_unregister_client(struct ntb_client *drvr);
int ntb_register_client_dev(char *device_name);
int ntb_register_client_dev(char *device_name);