|
| 1 | +// SPDX-License-Identifier: GPL |
| 2 | + |
| 3 | +/* Intel(R) QSFP Memory controller poller api |
| 4 | + * |
| 5 | + * Copyright (C) 2023 Intel Corporation. All rights reserved. |
| 6 | + * |
| 7 | + * Contributors: |
| 8 | + * Preetam Narayan |
| 9 | + */ |
| 10 | + |
| 11 | +#include "intel_fpga_eth_main.h" |
| 12 | +#include <linux/platform_device.h> |
| 13 | +#include <linux/of_platform.h> |
| 14 | + |
| 15 | + |
| 16 | +static struct platform_device * |
| 17 | +qsfp_lane_mapper(intel_fpga_xtile_eth_private *priv) { |
| 18 | + |
| 19 | + struct platform_device *pdev; |
| 20 | + struct platform_device *pdev_qsfp; |
| 21 | + struct device_node *dev_qsfp; |
| 22 | + |
| 23 | + pdev = container_of(priv->device, struct platform_device, dev); |
| 24 | + |
| 25 | + /* QSFP has four lanes, each lane is considered one port and |
| 26 | + * corresponds to linux network interface |
| 27 | + */ |
| 28 | + if (priv->qsfp_lane >= 0 && priv->qsfp_lane <=3) |
| 29 | + dev_qsfp = of_parse_phandle(pdev->dev.of_node, "qsfp0", 0); |
| 30 | + else |
| 31 | + dev_qsfp = of_parse_phandle(pdev->dev.of_node, "qsfp1", 0); |
| 32 | + |
| 33 | + pdev_qsfp = of_find_device_by_node(dev_qsfp); |
| 34 | + |
| 35 | + return pdev_qsfp; |
| 36 | +} |
| 37 | + |
| 38 | +static void |
| 39 | +qsfp_addr_space_mapper(intel_fpga_xtile_eth_private *priv, |
| 40 | + struct platform_device *pdev_qsfp) { |
| 41 | + |
| 42 | + struct resource *qsfp_ctrl_res; |
| 43 | + |
| 44 | + qsfp_ctrl_res = |
| 45 | + platform_get_resource_byname(pdev_qsfp, |
| 46 | + IORESOURCE_MEM, |
| 47 | + "qsfp-mem-ctrl"); |
| 48 | + |
| 49 | + priv->qsfp_reg = devm_ioremap(&pdev_qsfp->dev, |
| 50 | + qsfp_ctrl_res->start, |
| 51 | + resource_size(qsfp_ctrl_res)); |
| 52 | +} |
| 53 | + |
| 54 | +void qsfp_link_status(struct work_struct *work) { |
| 55 | + |
| 56 | + bool is_link_stable; |
| 57 | + struct delayed_work *dwork; |
| 58 | + bool is_next_iter_fine = false; |
| 59 | + intel_fpga_xtile_eth_private *priv; |
| 60 | + static bool is_prev_iter_fine = true; |
| 61 | + |
| 62 | + dwork = to_delayed_work(work); |
| 63 | + priv = container_of(dwork, intel_fpga_xtile_eth_private, dwork); |
| 64 | + |
| 65 | + priv->cable_unplugged = |
| 66 | + priv->qsfp_reg->status_reg.qsfp_stat_bits.mod_presence; |
| 67 | + |
| 68 | + is_link_stable = |
| 69 | + hssi_ethport_is_stable(priv->pdev_hssi, priv->chan, false); |
| 70 | + |
| 71 | + is_next_iter_fine = |
| 72 | + (is_link_stable == true) && (priv->cable_unplugged == false); |
| 73 | + |
| 74 | + /* If the link is not stable to perform the networking function then |
| 75 | + * necessary defence need to be taken |
| 76 | + */ |
| 77 | + if (is_prev_iter_fine == is_next_iter_fine) |
| 78 | + /* This is for the 1st iteration where it is assumed link is up |
| 79 | + * because on ndo_open system has been prior initalized |
| 80 | + */ |
| 81 | + goto reshed; |
| 82 | + |
| 83 | + else if (is_next_iter_fine == true) { |
| 84 | + if ( priv->qsfp_ops->qsfp_link_up ) |
| 85 | + priv->qsfp_ops->qsfp_link_up(priv); |
| 86 | + } |
| 87 | + else { |
| 88 | + if ( priv->qsfp_ops->qsfp_link_down ) |
| 89 | + priv->qsfp_ops->qsfp_link_down(priv); |
| 90 | + } |
| 91 | + |
| 92 | + is_prev_iter_fine = is_next_iter_fine; |
| 93 | + |
| 94 | +reshed: |
| 95 | + schedule_delayed_work(&priv->dwork, msecs_to_jiffies(QSFP_POLL_TIMEOUT)); |
| 96 | +} |
| 97 | + |
| 98 | + |
| 99 | +static void |
| 100 | +init_worker_thread(intel_fpga_xtile_eth_private *priv) { |
| 101 | + |
| 102 | + INIT_DELAYED_WORK(&priv->dwork, qsfp_link_status); |
| 103 | + qsfp_link_status(&priv->dwork.work); |
| 104 | +} |
| 105 | + |
| 106 | +void init_qsfp_ctrl_space(intel_fpga_xtile_eth_private *priv) { |
| 107 | + |
| 108 | + struct platform_device *pdev_qsfp; |
| 109 | + |
| 110 | + pdev_qsfp = qsfp_lane_mapper(priv); |
| 111 | + qsfp_addr_space_mapper(priv, pdev_qsfp); |
| 112 | + |
| 113 | + init_worker_thread(priv); |
| 114 | +} |
| 115 | + |
| 116 | +static void |
| 117 | +release_worker_thread(intel_fpga_xtile_eth_private *priv) { |
| 118 | + cancel_delayed_work_sync(&priv->dwork); |
| 119 | +} |
| 120 | + |
| 121 | +void deinit_qsfp_ctrl_space(intel_fpga_xtile_eth_private *priv) { |
| 122 | + release_worker_thread(priv); |
| 123 | +} |
0 commit comments