mirror of
https://github.com/torvalds/linux.git
synced 2026-09-24 06:24:02 +02:00
ixd: add reset checks and initialize the mailbox
At the end of the probe, trigger hard reset, initialize and schedule the after-reset task. If the reset is complete in a pre-determined time, initialize the default mailbox, through which other resources will be negotiated. Co-developed-by: Amritha Nambiar <amritha.nambiar@intel.com> Signed-off-by: Amritha Nambiar <amritha.nambiar@intel.com> Reviewed-by: Maciej Fijalkowski <maciej.fijalkowski@intel.com> Reviewed-by: Aleksandr Loktionov <aleksandr.loktionov@intel.com> Tested-by: Bharath R <Bharath.r@intel.com> Signed-off-by: Larysa Zaremba <larysa.zaremba@intel.com> Signed-off-by: Tony Nguyen <anthony.l.nguyen@intel.com>
This commit is contained in:
parent
bea44e3892
commit
31ddf7965a
|
|
@ -4,6 +4,7 @@
|
|||
config IXD
|
||||
tristate "Intel(R) Control Plane Function Support"
|
||||
depends on PCI_MSI
|
||||
select LIBIE_CP
|
||||
select LIBIE_PCI
|
||||
help
|
||||
This driver supports Intel(R) Control Plane PCI Function
|
||||
|
|
|
|||
|
|
@ -6,3 +6,5 @@
|
|||
obj-$(CONFIG_IXD) += ixd.o
|
||||
|
||||
ixd-y := ixd_main.o
|
||||
ixd-y += ixd_dev.o
|
||||
ixd-y += ixd_lib.o
|
||||
|
|
|
|||
|
|
@ -4,14 +4,29 @@
|
|||
#ifndef _IXD_H_
|
||||
#define _IXD_H_
|
||||
|
||||
#include <linux/net/intel/libie/pci.h>
|
||||
#include <linux/net/intel/libie/controlq.h>
|
||||
|
||||
#define IXD_INIT_TASK_DELAY_JIFFIES msecs_to_jiffies(500)
|
||||
|
||||
/**
|
||||
* struct ixd_adapter - Data structure representing a CPF
|
||||
* @hw: Device access data
|
||||
* @cp_ctx: Control plane communication context
|
||||
* @init_task: Delayed initialization after reset
|
||||
* @init_task.init_work: Delayed initialization work
|
||||
* @init_task.reset_retries: How many times to check, whether reset is completed
|
||||
* @xnm: virtchnl transaction manager
|
||||
* @asq: Send control queue info
|
||||
* @arq: Receive control queue info
|
||||
*/
|
||||
struct ixd_adapter {
|
||||
struct libie_mmio_info hw;
|
||||
struct libie_ctlq_ctx cp_ctx;
|
||||
struct {
|
||||
struct delayed_work init_work;
|
||||
u8 reset_retries;
|
||||
} init_task;
|
||||
struct libie_ctlq_xn_manager *xnm;
|
||||
struct libie_ctlq_info *asq;
|
||||
struct libie_ctlq_info *arq;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -22,7 +37,16 @@ struct ixd_adapter {
|
|||
*/
|
||||
static inline struct device *ixd_to_dev(struct ixd_adapter *adapter)
|
||||
{
|
||||
return &adapter->hw.pdev->dev;
|
||||
return &adapter->cp_ctx.mmio_info.pdev->dev;
|
||||
}
|
||||
|
||||
void ixd_ctlq_reg_init(struct ixd_adapter *adapter,
|
||||
struct libie_ctlq_reg *ctlq_reg_tx,
|
||||
struct libie_ctlq_reg *ctlq_reg_rx);
|
||||
void ixd_trigger_reset(struct ixd_adapter *adapter);
|
||||
bool ixd_check_reset_complete(struct ixd_adapter *adapter);
|
||||
void ixd_init_task(struct work_struct *work);
|
||||
int ixd_init_dflt_mbx(struct ixd_adapter *adapter);
|
||||
void ixd_deinit_dflt_mbx(struct ixd_adapter *adapter);
|
||||
|
||||
#endif /* _IXD_H_ */
|
||||
|
|
|
|||
89
drivers/net/ethernet/intel/ixd/ixd_dev.c
Normal file
89
drivers/net/ethernet/intel/ixd/ixd_dev.c
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* Copyright (C) 2025 Intel Corporation */
|
||||
|
||||
#include "ixd.h"
|
||||
#include "ixd_lan_regs.h"
|
||||
|
||||
/**
|
||||
* ixd_ctlq_reg_init - Initialize default mailbox registers
|
||||
* @adapter: PCI device driver-specific private data
|
||||
* @ctlq_reg_tx: Transmit queue registers info to be filled
|
||||
* @ctlq_reg_rx: Receive queue registers info to be filled
|
||||
*/
|
||||
void ixd_ctlq_reg_init(struct ixd_adapter *adapter,
|
||||
struct libie_ctlq_reg *ctlq_reg_tx,
|
||||
struct libie_ctlq_reg *ctlq_reg_rx)
|
||||
{
|
||||
struct libie_mmio_info *mmio_info = &adapter->cp_ctx.mmio_info;
|
||||
*ctlq_reg_tx = (struct libie_ctlq_reg) {
|
||||
.head = libie_pci_get_mmio_addr(mmio_info, PF_FW_ATQH),
|
||||
.tail = libie_pci_get_mmio_addr(mmio_info, PF_FW_ATQT),
|
||||
.len = libie_pci_get_mmio_addr(mmio_info, PF_FW_ATQLEN),
|
||||
.addr_high = libie_pci_get_mmio_addr(mmio_info, PF_FW_ATQBAH),
|
||||
.addr_low = libie_pci_get_mmio_addr(mmio_info, PF_FW_ATQBAL),
|
||||
.len_mask = PF_FW_ATQLEN_ATQLEN_M,
|
||||
.len_ena_mask = PF_FW_ATQLEN_ATQENABLE_M,
|
||||
.head_mask = PF_FW_ATQH_ATQH_M,
|
||||
};
|
||||
|
||||
*ctlq_reg_rx = (struct libie_ctlq_reg) {
|
||||
.head = libie_pci_get_mmio_addr(mmio_info, PF_FW_ARQH),
|
||||
.tail = libie_pci_get_mmio_addr(mmio_info, PF_FW_ARQT),
|
||||
.len = libie_pci_get_mmio_addr(mmio_info, PF_FW_ARQLEN),
|
||||
.addr_high = libie_pci_get_mmio_addr(mmio_info, PF_FW_ARQBAH),
|
||||
.addr_low = libie_pci_get_mmio_addr(mmio_info, PF_FW_ARQBAL),
|
||||
.len_mask = PF_FW_ARQLEN_ARQLEN_M,
|
||||
.len_ena_mask = PF_FW_ARQLEN_ARQENABLE_M,
|
||||
.head_mask = PF_FW_ARQH_ARQH_M,
|
||||
};
|
||||
}
|
||||
|
||||
static const struct ixd_reset_reg ixd_reset_reg = {
|
||||
.rstat = PFGEN_RSTAT,
|
||||
.rstat_m = PFGEN_RSTAT_PFR_STATE_M,
|
||||
.rstat_ok_v = 0b01,
|
||||
.rtrigger = PFGEN_CTRL,
|
||||
.rtrigger_m = PFGEN_CTRL_PFSWR,
|
||||
};
|
||||
|
||||
/**
|
||||
* ixd_trigger_reset - Trigger PFR reset
|
||||
* @adapter: the device with mapped reset register
|
||||
*/
|
||||
void ixd_trigger_reset(struct ixd_adapter *adapter)
|
||||
{
|
||||
void __iomem *addr;
|
||||
u32 reg_val;
|
||||
|
||||
addr = libie_pci_get_mmio_addr(&adapter->cp_ctx.mmio_info,
|
||||
ixd_reset_reg.rtrigger);
|
||||
reg_val = readl(addr);
|
||||
writel(reg_val | ixd_reset_reg.rtrigger_m, addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* ixd_check_reset_complete - Check if the PFR reset is completed
|
||||
* @adapter: CPF being reset
|
||||
*
|
||||
* Return: %true if the register read indicates reset has been finished,
|
||||
* %false otherwise
|
||||
*/
|
||||
bool ixd_check_reset_complete(struct ixd_adapter *adapter)
|
||||
{
|
||||
u32 reg_val, reset_status;
|
||||
void __iomem *addr;
|
||||
|
||||
addr = libie_pci_get_mmio_addr(&adapter->cp_ctx.mmio_info,
|
||||
ixd_reset_reg.rstat);
|
||||
reg_val = readl(addr);
|
||||
reset_status = reg_val & ixd_reset_reg.rstat_m;
|
||||
|
||||
/* 0xFFFFFFFF might be read if the other side hasn't cleared
|
||||
* the register for us yet.
|
||||
*/
|
||||
if (reg_val != GENMASK(31, 0) &&
|
||||
reset_status == ixd_reset_reg.rstat_ok_v)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -11,9 +11,33 @@
|
|||
#define PF_FW_MBX_REG_LEN 4096
|
||||
#define PF_FW_MBX 0x08400000
|
||||
|
||||
#define PF_FW_ARQBAL (PF_FW_MBX)
|
||||
#define PF_FW_ARQBAH (PF_FW_MBX + 0x4)
|
||||
#define PF_FW_ARQLEN (PF_FW_MBX + 0x8)
|
||||
#define PF_FW_ARQLEN_ARQLEN_M GENMASK(12, 0)
|
||||
#define PF_FW_ARQLEN_ARQENABLE_S 31
|
||||
#define PF_FW_ARQLEN_ARQENABLE_M BIT(PF_FW_ARQLEN_ARQENABLE_S)
|
||||
#define PF_FW_ARQH_ARQH_M GENMASK(12, 0)
|
||||
#define PF_FW_ARQH (PF_FW_MBX + 0xC)
|
||||
#define PF_FW_ARQT (PF_FW_MBX + 0x10)
|
||||
|
||||
#define PF_FW_ATQBAL (PF_FW_MBX + 0x14)
|
||||
#define PF_FW_ATQBAH (PF_FW_MBX + 0x18)
|
||||
#define PF_FW_ATQLEN (PF_FW_MBX + 0x1C)
|
||||
#define PF_FW_ATQLEN_ATQLEN_M GENMASK(9, 0)
|
||||
#define PF_FW_ATQLEN_ATQENABLE_S 31
|
||||
#define PF_FW_ATQLEN_ATQENABLE_M BIT(PF_FW_ATQLEN_ATQENABLE_S)
|
||||
#define PF_FW_ATQH_ATQH_M GENMASK(9, 0)
|
||||
#define PF_FW_ATQH (PF_FW_MBX + 0x20)
|
||||
#define PF_FW_ATQT (PF_FW_MBX + 0x24)
|
||||
|
||||
/* Reset registers */
|
||||
#define PFGEN_RTRIG_REG_LEN 2048
|
||||
#define PFGEN_RTRIG 0x08407000 /* Device resets */
|
||||
#define PFGEN_RSTAT 0x08407008 /* PFR status */
|
||||
#define PFGEN_RSTAT_PFR_STATE_M GENMASK(1, 0)
|
||||
#define PFGEN_CTRL 0x0840700C /* PFR trigger */
|
||||
#define PFGEN_CTRL_PFSWR BIT(0)
|
||||
|
||||
/**
|
||||
* struct ixd_bar_region - BAR region description
|
||||
|
|
@ -25,4 +49,20 @@ struct ixd_bar_region {
|
|||
resource_size_t size;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct ixd_reset_reg - structure for reset registers
|
||||
* @rstat: offset of status in register
|
||||
* @rstat_m: status mask
|
||||
* @rstat_ok_v: value that indicates PFR completed status
|
||||
* @rtrigger: offset of reset trigger in register
|
||||
* @rtrigger_m: reset trigger mask
|
||||
*/
|
||||
struct ixd_reset_reg {
|
||||
u32 rstat;
|
||||
u32 rstat_m;
|
||||
u32 rstat_ok_v;
|
||||
u32 rtrigger;
|
||||
u32 rtrigger_m;
|
||||
};
|
||||
|
||||
#endif /* _IXD_LAN_REGS_H_ */
|
||||
|
|
|
|||
136
drivers/net/ethernet/intel/ixd/ixd_lib.c
Normal file
136
drivers/net/ethernet/intel/ixd/ixd_lib.c
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* Copyright (C) 2025 Intel Corporation */
|
||||
|
||||
#include "ixd.h"
|
||||
|
||||
#define IXD_DFLT_MBX_Q_LEN 64
|
||||
|
||||
/**
|
||||
* ixd_init_ctlq_create_info - Initialize control queue info for creation
|
||||
* @info: destination
|
||||
* @type: type of the queue to create
|
||||
* @ctlq_reg: register assigned to the control queue
|
||||
*/
|
||||
static void ixd_init_ctlq_create_info(struct libie_ctlq_create_info *info,
|
||||
enum libie_ctlq_type type,
|
||||
const struct libie_ctlq_reg *ctlq_reg)
|
||||
{
|
||||
*info = (struct libie_ctlq_create_info) {
|
||||
.type = type,
|
||||
.id = -1,
|
||||
.reg = *ctlq_reg,
|
||||
.len = IXD_DFLT_MBX_Q_LEN,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* ixd_init_libie_xn_params - Initialize xn transaction manager creation info
|
||||
* @params: destination
|
||||
* @adapter: adapter info struct
|
||||
* @ctlqs: list of the managed queues to create
|
||||
* @num_queues: length of the queue list
|
||||
*/
|
||||
static void ixd_init_libie_xn_params(struct libie_ctlq_xn_init_params *params,
|
||||
struct ixd_adapter *adapter,
|
||||
struct libie_ctlq_create_info *ctlqs,
|
||||
uint num_queues)
|
||||
{
|
||||
*params = (struct libie_ctlq_xn_init_params){
|
||||
.cctlq_info = ctlqs,
|
||||
.ctx = &adapter->cp_ctx,
|
||||
.num_qs = num_queues,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* ixd_adapter_fill_dflt_ctlqs - Find default control queues and store them
|
||||
* @adapter: adapter info struct
|
||||
*/
|
||||
static void ixd_adapter_fill_dflt_ctlqs(struct ixd_adapter *adapter)
|
||||
{
|
||||
adapter->arq = libie_find_ctlq(&adapter->cp_ctx, LIBIE_CTLQ_TYPE_RX,
|
||||
LIBIE_CTLQ_MBX_ID);
|
||||
adapter->asq = libie_find_ctlq(&adapter->cp_ctx, LIBIE_CTLQ_TYPE_TX,
|
||||
LIBIE_CTLQ_MBX_ID);
|
||||
}
|
||||
|
||||
/**
|
||||
* ixd_deinit_dflt_mbx - Deinitialize default mailbox
|
||||
* @adapter: adapter info struct
|
||||
*/
|
||||
void ixd_deinit_dflt_mbx(struct ixd_adapter *adapter)
|
||||
{
|
||||
if (adapter->xnm)
|
||||
libie_ctlq_xn_deinit(adapter->xnm, &adapter->cp_ctx);
|
||||
|
||||
adapter->arq = NULL;
|
||||
adapter->asq = NULL;
|
||||
adapter->xnm = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* ixd_init_dflt_mbx - Setup default mailbox parameters and make request
|
||||
* @adapter: adapter info struct
|
||||
*
|
||||
* Return: %0 on success, negative errno code on failure
|
||||
*/
|
||||
int ixd_init_dflt_mbx(struct ixd_adapter *adapter)
|
||||
{
|
||||
struct libie_ctlq_create_info ctlqs_info[2];
|
||||
struct libie_ctlq_xn_init_params xn_params;
|
||||
struct libie_ctlq_reg ctlq_reg_tx;
|
||||
struct libie_ctlq_reg ctlq_reg_rx;
|
||||
int err;
|
||||
|
||||
ixd_ctlq_reg_init(adapter, &ctlq_reg_tx, &ctlq_reg_rx);
|
||||
ixd_init_ctlq_create_info(&ctlqs_info[0], LIBIE_CTLQ_TYPE_TX,
|
||||
&ctlq_reg_tx);
|
||||
ixd_init_ctlq_create_info(&ctlqs_info[1], LIBIE_CTLQ_TYPE_RX,
|
||||
&ctlq_reg_rx);
|
||||
ixd_init_libie_xn_params(&xn_params, adapter, ctlqs_info,
|
||||
ARRAY_SIZE(ctlqs_info));
|
||||
err = libie_ctlq_xn_init(&xn_params);
|
||||
if (err)
|
||||
return err;
|
||||
adapter->xnm = xn_params.xnm;
|
||||
|
||||
ixd_adapter_fill_dflt_ctlqs(adapter);
|
||||
|
||||
if (!adapter->asq || !adapter->arq) {
|
||||
ixd_deinit_dflt_mbx(adapter);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ixd_init_task - Initialize after reset
|
||||
* @work: init work struct
|
||||
*/
|
||||
void ixd_init_task(struct work_struct *work)
|
||||
{
|
||||
struct ixd_adapter *adapter;
|
||||
int err;
|
||||
|
||||
adapter = container_of(work, struct ixd_adapter,
|
||||
init_task.init_work.work);
|
||||
|
||||
if (!ixd_check_reset_complete(adapter)) {
|
||||
if (++adapter->init_task.reset_retries < 10)
|
||||
queue_delayed_work(system_dfl_wq,
|
||||
&adapter->init_task.init_work,
|
||||
IXD_INIT_TASK_DELAY_JIFFIES);
|
||||
else
|
||||
dev_err(ixd_to_dev(adapter),
|
||||
"Device reset failed. The driver was unable to contact the device's firmware. Check that the FW is running.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
adapter->init_task.reset_retries = 0;
|
||||
err = ixd_init_dflt_mbx(adapter);
|
||||
if (err)
|
||||
dev_err(ixd_to_dev(adapter),
|
||||
"Failed to initialize the default mailbox: %pe\n",
|
||||
ERR_PTR(err));
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@
|
|||
#include "ixd_lan_regs.h"
|
||||
|
||||
MODULE_DESCRIPTION("Intel(R) Control Plane Function Device Driver");
|
||||
MODULE_IMPORT_NS("LIBIE_CP");
|
||||
MODULE_IMPORT_NS("LIBIE_PCI");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
|
@ -16,7 +17,15 @@ static void ixd_remove(struct pci_dev *pdev)
|
|||
{
|
||||
struct ixd_adapter *adapter = pci_get_drvdata(pdev);
|
||||
|
||||
libie_pci_unmap_all_mmio_regions(&adapter->hw);
|
||||
/* Do not mix removal with (re)initialization */
|
||||
cancel_delayed_work_sync(&adapter->init_task.init_work);
|
||||
/* Leave the device clean on exit */
|
||||
if (adapter->xnm)
|
||||
libie_ctlq_xn_shutdown(adapter->xnm);
|
||||
ixd_trigger_reset(adapter);
|
||||
ixd_deinit_dflt_mbx(adapter);
|
||||
|
||||
libie_pci_unmap_all_mmio_regions(&adapter->cp_ctx.mmio_info);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -51,7 +60,7 @@ static int ixd_iomap_regions(struct ixd_adapter *adapter)
|
|||
};
|
||||
|
||||
for (int i = 0; i < ARRAY_SIZE(regions); i++) {
|
||||
struct libie_mmio_info *mmio_info = &adapter->hw;
|
||||
struct libie_mmio_info *mmio_info = &adapter->cp_ctx.mmio_info;
|
||||
bool map_ok;
|
||||
|
||||
map_ok = libie_pci_map_mmio_region(mmio_info,
|
||||
|
|
@ -84,8 +93,9 @@ static int ixd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
adapter = devm_kzalloc(&pdev->dev, sizeof(*adapter), GFP_KERNEL);
|
||||
if (!adapter)
|
||||
return -ENOMEM;
|
||||
adapter->hw.pdev = pdev;
|
||||
INIT_LIST_HEAD(&adapter->hw.mmio_list);
|
||||
|
||||
adapter->cp_ctx.mmio_info.pdev = pdev;
|
||||
INIT_LIST_HEAD(&adapter->cp_ctx.mmio_info.mmio_list);
|
||||
|
||||
err = libie_pci_init_dev(pdev);
|
||||
if (err)
|
||||
|
|
@ -93,7 +103,18 @@ static int ixd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
|
||||
pci_set_drvdata(pdev, adapter);
|
||||
|
||||
return ixd_iomap_regions(adapter);
|
||||
err = ixd_iomap_regions(adapter);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
INIT_DELAYED_WORK(&adapter->init_task.init_work,
|
||||
ixd_init_task);
|
||||
|
||||
ixd_trigger_reset(adapter);
|
||||
queue_delayed_work(system_dfl_wq, &adapter->init_task.init_work,
|
||||
IXD_INIT_TASK_DELAY_JIFFIES);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pci_device_id ixd_pci_tbl[] = {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user