diff options
Diffstat (limited to 'drivers/infiniband/hw/hfi1/init.c')
| -rw-r--r-- | drivers/infiniband/hw/hfi1/init.c | 104 | 
1 files changed, 64 insertions, 40 deletions
diff --git a/drivers/infiniband/hw/hfi1/init.c b/drivers/infiniband/hw/hfi1/init.c index 60db61536fed..e3b5bc93bc70 100644 --- a/drivers/infiniband/hw/hfi1/init.c +++ b/drivers/infiniband/hw/hfi1/init.c @@ -144,6 +144,8 @@ int hfi1_create_ctxts(struct hfi1_devdata *dd)  		struct hfi1_ctxtdata *rcd;  		ppd = dd->pport + (i % dd->num_pports); + +		/* dd->rcd[i] gets assigned inside the callee */  		rcd = hfi1_create_ctxtdata(ppd, i, dd->node);  		if (!rcd) {  			dd_dev_err(dd, @@ -169,8 +171,6 @@ int hfi1_create_ctxts(struct hfi1_devdata *dd)  		if (!rcd->sc) {  			dd_dev_err(dd,  				   "Unable to allocate kernel send context, failing\n"); -			dd->rcd[rcd->ctxt] = NULL; -			hfi1_free_ctxtdata(dd, rcd);  			goto nomem;  		} @@ -178,9 +178,6 @@ int hfi1_create_ctxts(struct hfi1_devdata *dd)  		if (ret < 0) {  			dd_dev_err(dd,  				   "Failed to setup kernel receive context, failing\n"); -			sc_free(rcd->sc); -			dd->rcd[rcd->ctxt] = NULL; -			hfi1_free_ctxtdata(dd, rcd);  			ret = -EFAULT;  			goto bail;  		} @@ -196,6 +193,10 @@ int hfi1_create_ctxts(struct hfi1_devdata *dd)  nomem:  	ret = -ENOMEM;  bail: +	if (dd->rcd) { +		for (i = 0; i < dd->num_rcv_contexts; ++i) +			hfi1_free_ctxtdata(dd, dd->rcd[i]); +	}  	kfree(dd->rcd);  	dd->rcd = NULL;  	return ret; @@ -216,7 +217,7 @@ struct hfi1_ctxtdata *hfi1_create_ctxtdata(struct hfi1_pportdata *ppd, u32 ctxt,  	    dd->num_rcv_contexts - dd->first_user_ctxt)  		kctxt_ngroups = (dd->rcv_entries.nctxt_extra -  				 (dd->num_rcv_contexts - dd->first_user_ctxt)); -	rcd = kzalloc(sizeof(*rcd), GFP_KERNEL); +	rcd = kzalloc_node(sizeof(*rcd), GFP_KERNEL, numa);  	if (rcd) {  		u32 rcvtids, max_entries; @@ -261,13 +262,6 @@ struct hfi1_ctxtdata *hfi1_create_ctxtdata(struct hfi1_pportdata *ppd, u32 ctxt,  		}  		rcd->eager_base = base * dd->rcv_entries.group_size; -		/* Validate and initialize Rcv Hdr Q variables */ -		if (rcvhdrcnt % HDRQ_INCREMENT) { -			dd_dev_err(dd, -				   "ctxt%u: header queue count %d must be divisible by %lu\n", -				   rcd->ctxt, rcvhdrcnt, HDRQ_INCREMENT); -			goto bail; -		}  		rcd->rcvhdrq_cnt = rcvhdrcnt;  		rcd->rcvhdrqentsize = hfi1_hdrq_entsize;  		/* @@ -506,7 +500,6 @@ void hfi1_init_pportdata(struct pci_dev *pdev, struct hfi1_pportdata *ppd,  	INIT_WORK(&ppd->qsfp_info.qsfp_work, qsfp_event);  	mutex_init(&ppd->hls_lock); -	spin_lock_init(&ppd->sdma_alllock);  	spin_lock_init(&ppd->qsfp_info.qsfp_lock);  	ppd->qsfp_info.ppd = ppd; @@ -1399,28 +1392,43 @@ static void postinit_cleanup(struct hfi1_devdata *dd)  	hfi1_free_devdata(dd);  } +static int init_validate_rcvhdrcnt(struct device *dev, uint thecnt) +{ +	if (thecnt <= HFI1_MIN_HDRQ_EGRBUF_CNT) { +		hfi1_early_err(dev, "Receive header queue count too small\n"); +		return -EINVAL; +	} + +	if (thecnt > HFI1_MAX_HDRQ_EGRBUF_CNT) { +		hfi1_early_err(dev, +			       "Receive header queue count cannot be greater than %u\n", +			       HFI1_MAX_HDRQ_EGRBUF_CNT); +		return -EINVAL; +	} + +	if (thecnt % HDRQ_INCREMENT) { +		hfi1_early_err(dev, "Receive header queue count %d must be divisible by %lu\n", +			       thecnt, HDRQ_INCREMENT); +		return -EINVAL; +	} + +	return 0; +} +  static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)  {  	int ret = 0, j, pidx, initfail; -	struct hfi1_devdata *dd = ERR_PTR(-EINVAL); +	struct hfi1_devdata *dd;  	struct hfi1_pportdata *ppd;  	/* First, lock the non-writable module parameters */  	HFI1_CAP_LOCK();  	/* Validate some global module parameters */ -	if (rcvhdrcnt <= HFI1_MIN_HDRQ_EGRBUF_CNT) { -		hfi1_early_err(&pdev->dev, "Header queue  count too small\n"); -		ret = -EINVAL; -		goto bail; -	} -	if (rcvhdrcnt > HFI1_MAX_HDRQ_EGRBUF_CNT) { -		hfi1_early_err(&pdev->dev, -			       "Receive header queue count cannot be greater than %u\n", -			       HFI1_MAX_HDRQ_EGRBUF_CNT); -		ret = -EINVAL; +	ret = init_validate_rcvhdrcnt(&pdev->dev, rcvhdrcnt); +	if (ret)  		goto bail; -	} +  	/* use the encoding function as a sanitization check */  	if (!encode_rcv_header_entry_size(hfi1_hdrq_entsize)) {  		hfi1_early_err(&pdev->dev, "Invalid HdrQ Entry size %u\n", @@ -1461,26 +1469,25 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)  	if (ret)  		goto bail; -	/* -	 * Do device-specific initialization, function table setup, dd -	 * allocation, etc. -	 */ -	switch (ent->device) { -	case PCI_DEVICE_ID_INTEL0: -	case PCI_DEVICE_ID_INTEL1: -		dd = hfi1_init_dd(pdev, ent); -		break; -	default: +	if (!(ent->device == PCI_DEVICE_ID_INTEL0 || +	      ent->device == PCI_DEVICE_ID_INTEL1)) {  		hfi1_early_err(&pdev->dev,  			       "Failing on unknown Intel deviceid 0x%x\n",  			       ent->device);  		ret = -ENODEV; +		goto clean_bail;  	} -	if (IS_ERR(dd)) +	/* +	 * Do device-specific initialization, function table setup, dd +	 * allocation, etc. +	 */ +	dd = hfi1_init_dd(pdev, ent); + +	if (IS_ERR(dd)) {  		ret = PTR_ERR(dd); -	if (ret)  		goto clean_bail; /* error already printed */ +	}  	ret = create_workqueues(dd);  	if (ret) @@ -1538,12 +1545,31 @@ bail:  	return ret;  } +static void wait_for_clients(struct hfi1_devdata *dd) +{ +	/* +	 * Remove the device init value and complete the device if there is +	 * no clients or wait for active clients to finish. +	 */ +	if (atomic_dec_and_test(&dd->user_refcount)) +		complete(&dd->user_comp); + +	wait_for_completion(&dd->user_comp); +} +  static void remove_one(struct pci_dev *pdev)  {  	struct hfi1_devdata *dd = pci_get_drvdata(pdev);  	/* close debugfs files before ib unregister */  	hfi1_dbg_ibdev_exit(&dd->verbs_dev); + +	/* remove the /dev hfi1 interface */ +	hfi1_device_remove(dd); + +	/* wait for existing user space clients to finish */ +	wait_for_clients(dd); +  	/* unregister from IB core */  	hfi1_unregister_ib_device(dd); @@ -1558,8 +1584,6 @@ static void remove_one(struct pci_dev *pdev)  	/* wait until all of our (qsfp) queue_work() calls complete */  	flush_workqueue(ib_wq); -	hfi1_device_remove(dd); -  	postinit_cleanup(dd);  }  | 
