--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2020, Intel Corporation. */
+
+#include "ice.h"
+#include "ice_devlink.h"
+
+static const struct devlink_ops ice_devlink_ops = {
+};
+
+static void ice_devlink_free(void *devlink_ptr)
+{
+       devlink_free((struct devlink *)devlink_ptr);
+}
+
+/**
+ * ice_allocate_pf - Allocate devlink and return PF structure pointer
+ * @dev: the device to allocate for
+ *
+ * Allocate a devlink instance for this device and return the private area as
+ * the PF structure. The devlink memory is kept track of through devres by
+ * adding an action to remove it when unwinding.
+ */
+struct ice_pf *ice_allocate_pf(struct device *dev)
+{
+       struct devlink *devlink;
+
+       devlink = devlink_alloc(&ice_devlink_ops, sizeof(struct ice_pf));
+       if (!devlink)
+               return NULL;
+
+       /* Add an action to teardown the devlink when unwinding the driver */
+       if (devm_add_action(dev, ice_devlink_free, devlink)) {
+               devlink_free(devlink);
+               return NULL;
+       }
+
+       return devlink_priv(devlink);
+}
+
+/**
+ * ice_devlink_register - Register devlink interface for this PF
+ * @pf: the PF to register the devlink for.
+ *
+ * Register the devlink instance associated with this physical function.
+ *
+ * Return: zero on success or an error code on failure.
+ */
+int ice_devlink_register(struct ice_pf *pf)
+{
+       struct devlink *devlink = priv_to_devlink(pf);
+       struct device *dev = ice_pf_to_dev(pf);
+       int err;
+
+       err = devlink_register(devlink, dev);
+       if (err) {
+               dev_err(dev, "devlink registration failed: %d\n", err);
+               return err;
+       }
+
+       return 0;
+}
+
+/**
+ * ice_devlink_unregister - Unregister devlink resources for this PF.
+ * @pf: the PF structure to cleanup
+ *
+ * Releases resources used by devlink and cleans up associated memory.
+ */
+void ice_devlink_unregister(struct ice_pf *pf)
+{
+       devlink_unregister(priv_to_devlink(pf));
+}
+
+/**
+ * ice_devlink_create_port - Create a devlink port for this PF
+ * @pf: the PF to create a port for
+ *
+ * Create and register a devlink_port for this PF. Note that although each
+ * physical function is connected to a separate devlink instance, the port
+ * will still be numbered according to the physical function id.
+ *
+ * Return: zero on success or an error code on failure.
+ */
+int ice_devlink_create_port(struct ice_pf *pf)
+{
+       struct devlink *devlink = priv_to_devlink(pf);
+       struct ice_vsi *vsi = ice_get_main_vsi(pf);
+       struct device *dev = ice_pf_to_dev(pf);
+       int err;
+
+       if (!vsi) {
+               dev_err(dev, "%s: unable to find main VSI\n", __func__);
+               return -EIO;
+       }
+
+       devlink_port_attrs_set(&pf->devlink_port, DEVLINK_PORT_FLAVOUR_PHYSICAL,
+                              pf->hw.pf_id, false, 0, NULL, 0);
+       err = devlink_port_register(devlink, &pf->devlink_port, pf->hw.pf_id);
+       if (err) {
+               dev_err(dev, "devlink_port_register failed: %d\n", err);
+               return err;
+       }
+
+       return 0;
+}
+
+/**
+ * ice_devlink_destroy_port - Destroy the devlink_port for this PF
+ * @pf: the PF to cleanup
+ *
+ * Unregisters the devlink_port structure associated with this PF.
+ */
+void ice_devlink_destroy_port(struct ice_pf *pf)
+{
+       devlink_port_type_clear(&pf->devlink_port);
+       devlink_port_unregister(&pf->devlink_port);
+}
 
 #include "ice_lib.h"
 #include "ice_dcb_lib.h"
 #include "ice_dcb_nl.h"
+#include "ice_devlink.h"
 
 #define DRV_VERSION_MAJOR 0
 #define DRV_VERSION_MINOR 8
        u8 mac_addr[ETH_ALEN];
        int err;
 
+       err = ice_devlink_create_port(pf);
+       if (err)
+               return err;
+
        netdev = alloc_etherdev_mqs(sizeof(*np), vsi->alloc_txq,
                                    vsi->alloc_rxq);
-       if (!netdev)
-               return -ENOMEM;
+       if (!netdev) {
+               err = -ENOMEM;
+               goto err_destroy_devlink_port;
+       }
 
        vsi->netdev = netdev;
        np = netdev_priv(netdev);
 
        err = register_netdev(vsi->netdev);
        if (err)
-               return err;
+               goto err_destroy_devlink_port;
+
+       devlink_port_type_eth_set(&pf->devlink_port, vsi->netdev);
 
        netif_carrier_off(vsi->netdev);
 
        netif_tx_stop_all_queues(vsi->netdev);
 
        return 0;
+
+err_destroy_devlink_port:
+       ice_devlink_destroy_port(pf);
+
+       return err;
 }
 
 /**
                return err;
        }
 
-       pf = devm_kzalloc(dev, sizeof(*pf), GFP_KERNEL);
+       pf = ice_allocate_pf(dev);
        if (!pf)
                return -ENOMEM;
 
 
        pf->msg_enable = netif_msg_init(debug, ICE_DFLT_NETIF_M);
 
+       err = ice_devlink_register(pf);
+       if (err) {
+               dev_err(dev, "ice_devlink_register failed: %d\n", err);
+               goto err_exit_unroll;
+       }
+
 #ifndef CONFIG_DYNAMIC_DEBUG
        if (debug < -1)
                hw->debug_mask = debug;
        return 0;
 
 err_alloc_sw_unroll:
+       ice_devlink_destroy_port(pf);
        set_bit(__ICE_SERVICE_DIS, pf->state);
        set_bit(__ICE_DOWN, pf->state);
        devm_kfree(dev, pf->first_sw);
        ice_deinit_pf(pf);
        ice_deinit_hw(hw);
 err_exit_unroll:
+       ice_devlink_unregister(pf);
        pci_disable_pcie_error_reporting(pdev);
        return err;
 }
        set_bit(__ICE_DOWN, pf->state);
        ice_service_task_stop(pf);
 
+       ice_devlink_destroy_port(pf);
        ice_vsi_release_all(pf);
        ice_free_irq_msix_misc(pf);
        ice_for_each_vsi(pf, i) {
        }
        ice_deinit_pf(pf);
        ice_deinit_hw(&pf->hw);
+       ice_devlink_unregister(pf);
+
        /* Issue a PFR as part of the prescribed driver unload flow.  Do not
         * do it via ice_schedule_reset() since there is no need to rebuild
         * and the service task is already stopped.