Skip to content

Commit

Permalink
net/mlx5: Handle event of power detection in the PCIE slot
Browse files Browse the repository at this point in the history
Handle event of power state change in the PCIE slot. When the event
occurs, check if query power state and PCI power fields is supported. If
so, read these fields from MPEIN (management PCIE info) register and
issue a corresponding message.

Signed-off-by: Aya Levin <ayal@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
  • Loading branch information
Aya Levin authored and Saeed Mahameed committed Apr 5, 2019
1 parent b6460c7 commit 5d3c537
Showing 2 changed files with 76 additions and 0 deletions.
75 changes: 75 additions & 0 deletions drivers/net/ethernet/mellanox/mlx5/core/events.c
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@ struct mlx5_event_nb {
static int any_notifier(struct notifier_block *, unsigned long, void *);
static int temp_warn(struct notifier_block *, unsigned long, void *);
static int port_module(struct notifier_block *, unsigned long, void *);
static int pcie_core(struct notifier_block *, unsigned long, void *);

/* handler which forwards the event to events->nh, driver notifiers */
static int forward_event(struct notifier_block *, unsigned long, void *);
@@ -30,6 +31,7 @@ static struct mlx5_nb events_nbs_ref[] = {
{.nb.notifier_call = any_notifier, .event_type = MLX5_EVENT_TYPE_NOTIFY_ANY },
{.nb.notifier_call = temp_warn, .event_type = MLX5_EVENT_TYPE_TEMP_WARN_EVENT },
{.nb.notifier_call = port_module, .event_type = MLX5_EVENT_TYPE_PORT_MODULE_EVENT },
{.nb.notifier_call = pcie_core, .event_type = MLX5_EVENT_TYPE_GENERAL_EVENT },

/* Events to be forwarded (as is) to mlx5 core interfaces (mlx5e/mlx5_ib) */
{.nb.notifier_call = forward_event, .event_type = MLX5_EVENT_TYPE_PORT_CHANGE },
@@ -51,11 +53,14 @@ static struct mlx5_nb events_nbs_ref[] = {

struct mlx5_events {
struct mlx5_core_dev *dev;
struct workqueue_struct *wq;
struct mlx5_event_nb notifiers[ARRAY_SIZE(events_nbs_ref)];
/* driver notifier chain */
struct atomic_notifier_head nh;
/* port module events stats */
struct mlx5_pme_stats pme_stats;
/*pcie_core*/
struct work_struct pcie_core_work;
};

static const char *eqe_type_str(u8 type)
@@ -249,6 +254,69 @@ static int port_module(struct notifier_block *nb, unsigned long type, void *data
return NOTIFY_OK;
}

enum {
MLX5_PCI_POWER_COULD_NOT_BE_READ = 0x0,
MLX5_PCI_POWER_SUFFICIENT_REPORTED = 0x1,
MLX5_PCI_POWER_INSUFFICIENT_REPORTED = 0x2,
};

static void mlx5_pcie_event(struct work_struct *work)
{
u32 out[MLX5_ST_SZ_DW(mpein_reg)] = {0};
u32 in[MLX5_ST_SZ_DW(mpein_reg)] = {0};
struct mlx5_events *events;
struct mlx5_core_dev *dev;
u8 power_status;
u16 pci_power;

events = container_of(work, struct mlx5_events, pcie_core_work);
dev = events->dev;

if (!MLX5_CAP_MCAM_FEATURE(dev, pci_status_and_power))
return;

mlx5_core_access_reg(dev, in, sizeof(in), out, sizeof(out),
MLX5_REG_MPEIN, 0, 0);
power_status = MLX5_GET(mpein_reg, out, pwr_status);
pci_power = MLX5_GET(mpein_reg, out, pci_power);

switch (power_status) {
case MLX5_PCI_POWER_COULD_NOT_BE_READ:
mlx5_core_info_rl(dev,
"PCIe slot power capability was not advertised.\n");
break;
case MLX5_PCI_POWER_INSUFFICIENT_REPORTED:
mlx5_core_warn_rl(dev,
"Detected insufficient power on the PCIe slot (%uW).\n",
pci_power);
break;
case MLX5_PCI_POWER_SUFFICIENT_REPORTED:
mlx5_core_info_rl(dev,
"PCIe slot advertised sufficient power (%uW).\n",
pci_power);
break;
}
}

static int pcie_core(struct notifier_block *nb, unsigned long type, void *data)
{
struct mlx5_event_nb *event_nb = mlx5_nb_cof(nb,
struct mlx5_event_nb,
nb);
struct mlx5_events *events = event_nb->ctx;
struct mlx5_eqe *eqe = data;

switch (eqe->sub_type) {
case MLX5_GENERAL_SUBTYPE_PCI_POWER_CHANGE_EVENT:
queue_work(events->wq, &events->pcie_core_work);
break;
default:
return NOTIFY_DONE;
}

return NOTIFY_OK;
}

void mlx5_get_pme_stats(struct mlx5_core_dev *dev, struct mlx5_pme_stats *stats)
{
*stats = dev->priv.events->pme_stats;
@@ -277,11 +345,17 @@ int mlx5_events_init(struct mlx5_core_dev *dev)
ATOMIC_INIT_NOTIFIER_HEAD(&events->nh);
events->dev = dev;
dev->priv.events = events;
events->wq = create_singlethread_workqueue("mlx5_events");
if (!events->wq)
return -ENOMEM;
INIT_WORK(&events->pcie_core_work, mlx5_pcie_event);

return 0;
}

void mlx5_events_cleanup(struct mlx5_core_dev *dev)
{
destroy_workqueue(dev->priv.events->wq);
kvfree(dev->priv.events);
}

@@ -304,6 +378,7 @@ void mlx5_events_stop(struct mlx5_core_dev *dev)

for (i = ARRAY_SIZE(events_nbs_ref) - 1; i >= 0 ; i--)
mlx5_eq_notifier_unregister(dev, &events->notifiers[i].nb);
flush_workqueue(events->wq);
}

int mlx5_notifier_register(struct mlx5_core_dev *dev, struct notifier_block *nb)
1 change: 1 addition & 0 deletions include/linux/mlx5/device.h
Original file line number Diff line number Diff line change
@@ -361,6 +361,7 @@ enum {

enum {
MLX5_GENERAL_SUBTYPE_DELAY_DROP_TIMEOUT = 0x1,
MLX5_GENERAL_SUBTYPE_PCI_POWER_CHANGE_EVENT = 0x5,
};

enum {

0 comments on commit 5d3c537

Please sign in to comment.