RE: [PATCH net-next 4/4] net: mana: Support hibernation and kexec

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




> -----Original Message-----
> From: Dexuan Cui <decui@xxxxxxxxxxxxx>
> Sent: Friday, October 29, 2021 8:54 PM
> To: davem@xxxxxxxxxxxxx; kuba@xxxxxxxxxx; gustavoars@xxxxxxxxxx; Haiyang
> Zhang <haiyangz@xxxxxxxxxxxxx>; netdev@xxxxxxxxxxxxxxx
> Cc: KY Srinivasan <kys@xxxxxxxxxxxxx>; stephen@xxxxxxxxxxxxxxxxxx;
> wei.liu@xxxxxxxxxx; linux-kernel@xxxxxxxxxxxxxxx; linux-
> hyperv@xxxxxxxxxxxxxxx; Shachar Raindel <shacharr@xxxxxxxxxxxxx>; Paul
> Rosswurm <paulros@xxxxxxxxxxxxx>; olaf@xxxxxxxxx; vkuznets
> <vkuznets@xxxxxxxxxx>; Dexuan Cui <decui@xxxxxxxxxxxxx>
> Subject: [PATCH net-next 4/4] net: mana: Support hibernation and kexec
> 
> Implement the suspend/resume/shutdown callbacks for hibernation/kexec.
> 
> Add mana_gd_setup() and mana_gd_cleanup() for some common code, and
> use them in the mand_gd_* callbacks.
> 
> Reuse mana_probe/remove() for the hibernation path.
> 
> Signed-off-by: Dexuan Cui <decui@xxxxxxxxxxxxx>
> ---
>  .../net/ethernet/microsoft/mana/gdma_main.c   | 140 +++++++++++++-----
>  drivers/net/ethernet/microsoft/mana/mana.h    |   4 +-
>  drivers/net/ethernet/microsoft/mana/mana_en.c |  72 +++++++--
>  3 files changed, 164 insertions(+), 52 deletions(-)
> 
> diff --git a/drivers/net/ethernet/microsoft/mana/gdma_main.c
> b/drivers/net/ethernet/microsoft/mana/gdma_main.c
> index 599dfd5e6090..c96ac81212f7 100644
> --- a/drivers/net/ethernet/microsoft/mana/gdma_main.c
> +++ b/drivers/net/ethernet/microsoft/mana/gdma_main.c
> @@ -1258,6 +1258,52 @@ static void mana_gd_remove_irqs(struct pci_dev
> *pdev)
>  	gc->irq_contexts = NULL;
>  }
> 
> +static int mana_gd_setup(struct pci_dev *pdev)
> +{
> +	struct gdma_context *gc = pci_get_drvdata(pdev);
> +	int err;
> +
> +	mana_gd_init_registers(pdev);
> +	mana_smc_init(&gc->shm_channel, gc->dev, gc->shm_base);
> +
> +	err = mana_gd_setup_irqs(pdev);
> +	if (err)
> +		return err;
> +
> +	err = mana_hwc_create_channel(gc);
> +	if (err)
> +		goto remove_irq;
> +
> +	err = mana_gd_verify_vf_version(pdev);
> +	if (err)
> +		goto destroy_hwc;
> +
> +	err = mana_gd_query_max_resources(pdev);
> +	if (err)
> +		goto destroy_hwc;
> +
> +	err = mana_gd_detect_devices(pdev);
> +	if (err)
> +		goto destroy_hwc;
> +
> +	return 0;
> +
> +destroy_hwc:
> +	mana_hwc_destroy_channel(gc);
> +remove_irq:
> +	mana_gd_remove_irqs(pdev);
> +	return err;
> +}
> +
> +static void mana_gd_cleanup(struct pci_dev *pdev)
> +{
> +	struct gdma_context *gc = pci_get_drvdata(pdev);
> +
> +	mana_hwc_destroy_channel(gc);
> +
> +	mana_gd_remove_irqs(pdev);
> +}
> +
>  static int mana_gd_probe(struct pci_dev *pdev, const struct
> pci_device_id *ent)
>  {
>  	struct gdma_context *gc;
> @@ -1287,6 +1333,9 @@ static int mana_gd_probe(struct pci_dev *pdev,
> const struct pci_device_id *ent)
>  	if (!gc)
>  		goto release_region;
> 
> +	mutex_init(&gc->eq_test_event_mutex);
> +	pci_set_drvdata(pdev, gc);
> +
>  	bar0_va = pci_iomap(pdev, bar, 0);
>  	if (!bar0_va)
>  		goto free_gc;
> @@ -1294,47 +1343,23 @@ static int mana_gd_probe(struct pci_dev *pdev,
> const struct pci_device_id *ent)
>  	gc->bar0_va = bar0_va;
>  	gc->dev = &pdev->dev;
> 
> -	pci_set_drvdata(pdev, gc);
> -
> -	mana_gd_init_registers(pdev);
> 
> -	mana_smc_init(&gc->shm_channel, gc->dev, gc->shm_base);
> -
> -	err = mana_gd_setup_irqs(pdev);
> +	err = mana_gd_setup(pdev);
>  	if (err)
>  		goto unmap_bar;
> 
> -	mutex_init(&gc->eq_test_event_mutex);
> -
> -	err = mana_hwc_create_channel(gc);
> +	err = mana_probe(&gc->mana, false);
>  	if (err)
> -		goto remove_irq;
> -
> -	err = mana_gd_verify_vf_version(pdev);
> -	if (err)
> -		goto remove_irq;
> -
> -	err = mana_gd_query_max_resources(pdev);
> -	if (err)
> -		goto remove_irq;
> -
> -	err = mana_gd_detect_devices(pdev);
> -	if (err)
> -		goto remove_irq;
> -
> -	err = mana_probe(&gc->mana);
> -	if (err)
> -		goto clean_up_gdma;
> +		goto cleanup_gd;
> 
>  	return 0;
> 
> -clean_up_gdma:
> -	mana_hwc_destroy_channel(gc);
> -remove_irq:
> -	mana_gd_remove_irqs(pdev);
> +cleanup_gd:
> +	mana_gd_cleanup(pdev);
>  unmap_bar:
>  	pci_iounmap(pdev, bar0_va);
>  free_gc:
> +	pci_set_drvdata(pdev, NULL);
>  	vfree(gc);
>  release_region:
>  	pci_release_regions(pdev);
> @@ -1349,11 +1374,9 @@ static void mana_gd_remove(struct pci_dev *pdev)
>  {
>  	struct gdma_context *gc = pci_get_drvdata(pdev);
> 
> -	mana_remove(&gc->mana);
> +	mana_remove(&gc->mana, false);
> 
> -	mana_hwc_destroy_channel(gc);
> -
> -	mana_gd_remove_irqs(pdev);
> +	mana_gd_cleanup(pdev);
> 
>  	pci_iounmap(pdev, gc->bar0_va);
> 
> @@ -1364,6 +1387,52 @@ static void mana_gd_remove(struct pci_dev *pdev)
>  	pci_disable_device(pdev);
>  }
> 
> +/* The 'state' parameter is not used. */
> +static int mana_gd_suspend(struct pci_dev *pdev, pm_message_t state)
> +{
> +	struct gdma_context *gc = pci_get_drvdata(pdev);
> +
> +	mana_remove(&gc->mana, true);
> +
> +	mana_gd_cleanup(pdev);
> +
> +	return 0;
> +}
> +
> +/* In case the NIC hardware stops working, the suspend and resume
> callbacks will
> + * fail -- if this happens, it's safer to just report an error than try
> to undo
> + * what has been done.
> + */
> +static int mana_gd_resume(struct pci_dev *pdev)
> +{
> +	struct gdma_context *gc = pci_get_drvdata(pdev);
> +	int err;
> +
> +	err = mana_gd_setup(pdev);
> +	if (err)
> +		return err;
> +
> +	err = mana_probe(&gc->mana, true);
> +	if (err)
> +		return err;
> +
> +	return 0;
> +}
> +
> +/* Quiesce the device for kexec. This is also called upon
> reboot/shutdown. */
> +static void mana_gd_shutdown(struct pci_dev *pdev)
> +{
> +	struct gdma_context *gc = pci_get_drvdata(pdev);
> +
> +	dev_info(&pdev->dev, "Shutdown was calledd\n");
> +
> +	mana_remove(&gc->mana, true);
> +
> +	mana_gd_cleanup(pdev);
> +
> +	pci_disable_device(pdev);
> +}
> +
>  #ifndef PCI_VENDOR_ID_MICROSOFT
>  #define PCI_VENDOR_ID_MICROSOFT 0x1414
>  #endif
> @@ -1378,6 +1447,9 @@ static struct pci_driver mana_driver = {
>  	.id_table	= mana_id_table,
>  	.probe		= mana_gd_probe,
>  	.remove		= mana_gd_remove,
> +	.suspend	= mana_gd_suspend,
> +	.resume		= mana_gd_resume,
> +	.shutdown	= mana_gd_shutdown,
>  };
> 
>  module_pci_driver(mana_driver);
> diff --git a/drivers/net/ethernet/microsoft/mana/mana.h
> b/drivers/net/ethernet/microsoft/mana/mana.h
> index fc98a5ba5ed0..d047ee876f12 100644
> --- a/drivers/net/ethernet/microsoft/mana/mana.h
> +++ b/drivers/net/ethernet/microsoft/mana/mana.h
> @@ -374,8 +374,8 @@ int mana_alloc_queues(struct net_device *ndev);
>  int mana_attach(struct net_device *ndev);
>  int mana_detach(struct net_device *ndev, bool from_close);
> 
> -int mana_probe(struct gdma_dev *gd);
> -void mana_remove(struct gdma_dev *gd);
> +int mana_probe(struct gdma_dev *gd, bool resuming);
> +void mana_remove(struct gdma_dev *gd, bool suspending);
> 
>  extern const struct ethtool_ops mana_ethtool_ops;
> 
> diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c
> b/drivers/net/ethernet/microsoft/mana/mana_en.c
> index 4ff5a1fc506f..820585d45a61 100644
> --- a/drivers/net/ethernet/microsoft/mana/mana_en.c
> +++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
> @@ -1828,11 +1828,12 @@ static int mana_probe_port(struct mana_context
> *ac, int port_idx,
>  	return err;
>  }
> 
> -int mana_probe(struct gdma_dev *gd)
> +int mana_probe(struct gdma_dev *gd, bool resuming)
>  {
>  	struct gdma_context *gc = gd->gdma_context;
> +	struct mana_context *ac = gd->driver_data;
>  	struct device *dev = gc->dev;
> -	struct mana_context *ac;
> +	u16 num_ports = 0;
>  	int err;
>  	int i;
> 
> @@ -1844,44 +1845,70 @@ int mana_probe(struct gdma_dev *gd)
>  	if (err)
>  		return err;
> 
> -	ac = kzalloc(sizeof(*ac), GFP_KERNEL);
> -	if (!ac)
> -		return -ENOMEM;
> +	if (!resuming) {
> +		ac = kzalloc(sizeof(*ac), GFP_KERNEL);
> +		if (!ac)
> +			return -ENOMEM;
> 
> -	ac->gdma_dev = gd;
> -	ac->num_ports = 1;
> -	gd->driver_data = ac;
> +		ac->gdma_dev = gd;
> +		gd->driver_data = ac;
> +	}
> 
>  	err = mana_create_eq(ac);
>  	if (err)
>  		goto out;
> 
>  	err = mana_query_device_cfg(ac, MANA_MAJOR_VERSION,
> MANA_MINOR_VERSION,
> -				    MANA_MICRO_VERSION, &ac->num_ports);
> +				    MANA_MICRO_VERSION, &num_ports);
>  	if (err)
>  		goto out;
> 
> +	if (!resuming) {
> +		ac->num_ports = num_ports;
> +	} else {
> +		if (ac->num_ports != num_ports) {
> +			dev_err(dev, "The number of vPorts changed: %d->%d\n",
> +				ac->num_ports, num_ports);
> +			err = -EPROTO;
> +			goto out;
> +		}
> +	}
> +
> +	if (ac->num_ports == 0)
> +		dev_err(dev, "Failed to detect any vPort\n");
> +
>  	if (ac->num_ports > MAX_PORTS_IN_MANA_DEV)
>  		ac->num_ports = MAX_PORTS_IN_MANA_DEV;
> 
> -	for (i = 0; i < ac->num_ports; i++) {
> -		err = mana_probe_port(ac, i, &ac->ports[i]);
> -		if (err)
> -			break;
> +	if (!resuming) {
> +		for (i = 0; i < ac->num_ports; i++) {
> +			err = mana_probe_port(ac, i, &ac->ports[i]);
> +			if (err)
> +				break;
> +		}
> +	} else {
> +		for (i = 0; i < ac->num_ports; i++) {
> +			rtnl_lock();
> +			err = mana_attach(ac->ports[i]);
> +			rtnl_unlock();
> +			if (err)
> +				break;
> +		}
>  	}
>  out:
>  	if (err)
> -		mana_remove(gd);
> +		mana_remove(gd, false);

The "goto out" can happen in both resuming true/false cases,
should the error handling path deal with the two cases
differently?


Other parts look good.

Reviewed-by: Haiyang Zhang <haiyangz@xxxxxxxxxxxxx>


> 
>  	return err;
>  }
> 
> -void mana_remove(struct gdma_dev *gd)
> +void mana_remove(struct gdma_dev *gd, bool suspending)
>  {
>  	struct gdma_context *gc = gd->gdma_context;
>  	struct mana_context *ac = gd->driver_data;
>  	struct device *dev = gc->dev;
>  	struct net_device *ndev;
> +	int err;
>  	int i;
> 
>  	for (i = 0; i < ac->num_ports; i++) {
> @@ -1897,7 +1924,16 @@ void mana_remove(struct gdma_dev *gd)
>  		 */
>  		rtnl_lock();
> 
> -		mana_detach(ndev, false);
> +		err = mana_detach(ndev, false);
> +		if (err)
> +			netdev_err(ndev, "Failed to detach vPort %d: %d\n",
> +				   i, err);
> +
> +		if (suspending) {
> +			/* No need to unregister the ndev. */
> +			rtnl_unlock();
> +			continue;
> +		}
> 
>  		unregister_netdevice(ndev);
> 
> @@ -1910,6 +1946,10 @@ void mana_remove(struct gdma_dev *gd)
> 
>  out:
>  	mana_gd_deregister_device(gd);
> +
> +	if (suspending)
> +		return;
> +
>  	gd->driver_data = NULL;
>  	gd->gdma_context = NULL;
>  	kfree(ac);
> --
> 2.17.1





[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux