diff options
author | Sucheta Chakraborty <sucheta.chakraborty@qlogic.com> | 2013-08-23 13:38:27 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-08-27 15:21:14 -0400 |
commit | 2d8ebcab86051f2cd7f207edb513995348b78213 (patch) | |
tree | 54d0d6b5846f4aadf759e72e2396e88fa6544d33 /drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c | |
parent | fb859ed6916faeae6b44027d2e0738836a11e8c1 (diff) | |
download | op-kernel-dev-2d8ebcab86051f2cd7f207edb513995348b78213.zip op-kernel-dev-2d8ebcab86051f2cd7f207edb513995348b78213.tar.gz |
qlcnic: dcb: Register DCB AEN handler.
o Adapter sends Asynchronous Event Notifications to the driver when
there are changes in the switch or adapter DCBX configuration.
AEN handler updates the driver DCBX parameters.
Signed-off-by: Sucheta Chakraborty <sucheta.chakraborty@qlogic.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c')
-rw-r--r-- | drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c | 105 |
1 files changed, 103 insertions, 2 deletions
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c index e43866f..3477818 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c @@ -10,6 +10,7 @@ #define QLC_DCB_NUM_PARAM 3 +#define QLC_DCB_AEN_BIT 0x2 #define QLC_DCB_FW_VER 0x2 #define QLC_DCB_MAX_TC 0x8 #define QLC_DCB_MAX_APP 0x8 @@ -44,6 +45,8 @@ #define QLC_82XX_DCB_GET_PRIOMAP_APP(X) (1 << X) #define QLC_82XX_DCB_PRIO_TC_MAP (0x76543210) +static void qlcnic_dcb_aen_work(struct work_struct *); + static void __qlcnic_dcb_free(struct qlcnic_adapter *); static int __qlcnic_dcb_attach(struct qlcnic_adapter *); static int __qlcnic_dcb_query_hw_capability(struct qlcnic_adapter *, char *); @@ -52,10 +55,13 @@ static void __qlcnic_dcb_get_info(struct qlcnic_adapter *); static int qlcnic_82xx_dcb_get_hw_capability(struct qlcnic_adapter *); static int qlcnic_82xx_dcb_query_cee_param(struct qlcnic_adapter *, char *, u8); static int qlcnic_82xx_dcb_get_cee_cfg(struct qlcnic_adapter *); +static void qlcnic_82xx_dcb_handle_aen(struct qlcnic_adapter *, void *); static int qlcnic_83xx_dcb_get_hw_capability(struct qlcnic_adapter *); static int qlcnic_83xx_dcb_query_cee_param(struct qlcnic_adapter *, char *, u8); static int qlcnic_83xx_dcb_get_cee_cfg(struct qlcnic_adapter *); +static int qlcnic_83xx_dcb_register_aen(struct qlcnic_adapter *, bool); +static void qlcnic_83xx_dcb_handle_aen(struct qlcnic_adapter *, void *); struct qlcnic_dcb_capability { bool tsa_capability; @@ -102,6 +108,8 @@ static struct qlcnic_dcb_ops qlcnic_83xx_dcb_ops = { .get_hw_capability = qlcnic_83xx_dcb_get_hw_capability, .query_cee_param = qlcnic_83xx_dcb_query_cee_param, .get_cee_cfg = qlcnic_83xx_dcb_get_cee_cfg, + .register_aen = qlcnic_83xx_dcb_register_aen, + .handle_aen = qlcnic_83xx_dcb_handle_aen, }; static struct qlcnic_dcb_ops qlcnic_82xx_dcb_ops = { @@ -113,6 +121,7 @@ static struct qlcnic_dcb_ops qlcnic_82xx_dcb_ops = { .get_hw_capability = qlcnic_82xx_dcb_get_hw_capability, .query_cee_param = qlcnic_82xx_dcb_query_cee_param, .get_cee_cfg = qlcnic_82xx_dcb_get_cee_cfg, + .handle_aen = qlcnic_82xx_dcb_handle_aen, }; static u8 qlcnic_dcb_get_num_app(struct qlcnic_adapter *adapter, u32 val) @@ -140,6 +149,7 @@ int __qlcnic_register_dcb(struct qlcnic_adapter *adapter) return -ENOMEM; adapter->dcb = dcb; + dcb->adapter = adapter; qlcnic_set_dcb_ops(adapter); return 0; @@ -152,6 +162,18 @@ static void __qlcnic_dcb_free(struct qlcnic_adapter *adapter) if (!dcb) return; + qlcnic_dcb_register_aen(adapter, 0); + + while (test_bit(__QLCNIC_DCB_IN_AEN, &adapter->state)) + usleep_range(10000, 11000); + + cancel_delayed_work_sync(&dcb->aen_work); + + if (dcb->wq) { + destroy_workqueue(dcb->wq); + dcb->wq = NULL; + } + kfree(dcb->cfg); dcb->cfg = NULL; kfree(dcb->param); @@ -164,6 +186,7 @@ static void __qlcnic_dcb_get_info(struct qlcnic_adapter *adapter) { qlcnic_dcb_get_hw_capability(adapter); qlcnic_dcb_get_cee_cfg(adapter); + qlcnic_dcb_register_aen(adapter, 1); } static int __qlcnic_dcb_attach(struct qlcnic_adapter *adapter) @@ -171,9 +194,20 @@ static int __qlcnic_dcb_attach(struct qlcnic_adapter *adapter) struct qlcnic_dcb *dcb = adapter->dcb; int err = 0; + INIT_DELAYED_WORK(&dcb->aen_work, qlcnic_dcb_aen_work); + + dcb->wq = create_singlethread_workqueue("qlcnic-dcb"); + if (!dcb->wq) { + dev_err(&adapter->pdev->dev, + "DCB workqueue allocation failed. DCB will be disabled\n"); + return -1; + } + dcb->cfg = kzalloc(sizeof(struct qlcnic_dcb_cfg), GFP_ATOMIC); - if (!dcb->cfg) - return -ENOMEM; + if (!dcb->cfg) { + err = -ENOMEM; + goto out_free_wq; + } dcb->param = kzalloc(sizeof(struct qlcnic_dcb_mbx_params), GFP_ATOMIC); if (!dcb->param) { @@ -188,6 +222,10 @@ out_free_cfg: kfree(dcb->cfg); dcb->cfg = NULL; +out_free_wq: + destroy_workqueue(dcb->wq); + dcb->wq = NULL; + return err; } @@ -368,6 +406,29 @@ static int qlcnic_82xx_dcb_get_cee_cfg(struct qlcnic_adapter *adapter) return err; } +static void qlcnic_dcb_aen_work(struct work_struct *work) +{ + struct qlcnic_adapter *adapter; + struct qlcnic_dcb *dcb; + + dcb = container_of(work, struct qlcnic_dcb, aen_work.work); + adapter = dcb->adapter; + + qlcnic_dcb_get_cee_cfg(adapter); + clear_bit(__QLCNIC_DCB_IN_AEN, &adapter->state); +} + +static void qlcnic_82xx_dcb_handle_aen(struct qlcnic_adapter *adapter, + void *data) +{ + struct qlcnic_dcb *dcb = adapter->dcb; + + if (test_and_set_bit(__QLCNIC_DCB_IN_AEN, &adapter->state)) + return; + + queue_delayed_work(dcb->wq, &dcb->aen_work, 0); +} + static int qlcnic_83xx_dcb_get_hw_capability(struct qlcnic_adapter *adapter) { struct qlcnic_dcb_capability *cap = &adapter->dcb->cfg->capability; @@ -459,3 +520,43 @@ static int qlcnic_83xx_dcb_get_cee_cfg(struct qlcnic_adapter *adapter) return qlcnic_dcb_query_cee_param(adapter, (char *)dcb->param, 0); } + +static int qlcnic_83xx_dcb_register_aen(struct qlcnic_adapter *adapter, + bool flag) +{ + u8 val = (flag ? QLCNIC_CMD_INIT_NIC_FUNC : QLCNIC_CMD_STOP_NIC_FUNC); + struct qlcnic_cmd_args cmd; + int err; + + err = qlcnic_alloc_mbx_args(&cmd, adapter, val); + if (err) + return err; + + cmd.req.arg[1] = QLC_DCB_AEN_BIT; + + err = qlcnic_issue_cmd(adapter, &cmd); + if (err) + dev_err(&adapter->pdev->dev, "Failed to %s DCBX AEN, err %d\n", + (flag ? "register" : "unregister"), err); + + qlcnic_free_mbx_args(&cmd); + + return err; +} + +static void qlcnic_83xx_dcb_handle_aen(struct qlcnic_adapter *adapter, + void *data) +{ + struct qlcnic_dcb *dcb = adapter->dcb; + u32 *val = data; + + if (test_and_set_bit(__QLCNIC_DCB_IN_AEN, &adapter->state)) + return; + + if (*val & BIT_8) + set_bit(__QLCNIC_DCB_STATE, &adapter->state); + else + clear_bit(__QLCNIC_DCB_STATE, &adapter->state); + + queue_delayed_work(dcb->wq, &dcb->aen_work, 0); +} |