forked from Minki/linux
liquidio: moved octeon_setup_interrupt to lio_core.c
Moving common octeon_setup_interrupt to lio_core.c Signed-off-by: Intiyaz Basha <intiyaz.basha@cavium.com> Signed-off-by: Raghu Vatsavayi <raghu.vatsavayi@cavium.com> Signed-off-by: Felix Manlunas <felix.manlunas@cavium.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
5ef4ddb339
commit
14aec73aab
@ -864,6 +864,7 @@ static void liquidio_schedule_droq_pkt_handlers(struct octeon_device *oct)
|
||||
* @param irq unused
|
||||
* @param dev octeon device
|
||||
*/
|
||||
static
|
||||
irqreturn_t liquidio_legacy_intr_handler(int irq __attribute__((unused)),
|
||||
void *dev)
|
||||
{
|
||||
@ -884,3 +885,202 @@ irqreturn_t liquidio_legacy_intr_handler(int irq __attribute__((unused)),
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Setup interrupt for octeon device
|
||||
* @param oct octeon device
|
||||
*
|
||||
* Enable interrupt in Octeon device as given in the PCI interrupt mask.
|
||||
*/
|
||||
int octeon_setup_interrupt(struct octeon_device *oct)
|
||||
{
|
||||
struct msix_entry *msix_entries;
|
||||
char *queue_irq_names = NULL;
|
||||
int i, num_interrupts = 0;
|
||||
int num_alloc_ioq_vectors;
|
||||
char *aux_irq_name = NULL;
|
||||
int num_ioq_vectors;
|
||||
int irqret, err;
|
||||
|
||||
if (oct->msix_on) {
|
||||
if (OCTEON_CN23XX_PF(oct)) {
|
||||
oct->num_msix_irqs = oct->sriov_info.num_pf_rings;
|
||||
num_interrupts = MAX_IOQ_INTERRUPTS_PER_PF + 1;
|
||||
|
||||
/* one non ioq interrupt for handling
|
||||
* sli_mac_pf_int_sum
|
||||
*/
|
||||
oct->num_msix_irqs += 1;
|
||||
} else if (OCTEON_CN23XX_VF(oct)) {
|
||||
oct->num_msix_irqs = oct->sriov_info.rings_per_vf;
|
||||
num_interrupts = MAX_IOQ_INTERRUPTS_PER_VF;
|
||||
}
|
||||
|
||||
/* allocate storage for the names assigned to each irq */
|
||||
oct->irq_name_storage =
|
||||
kcalloc(num_interrupts, INTRNAMSIZ, GFP_KERNEL);
|
||||
if (!oct->irq_name_storage) {
|
||||
dev_err(&oct->pci_dev->dev, "Irq name storage alloc failed...\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
queue_irq_names = oct->irq_name_storage;
|
||||
|
||||
if (OCTEON_CN23XX_PF(oct))
|
||||
aux_irq_name = &queue_irq_names
|
||||
[IRQ_NAME_OFF(MAX_IOQ_INTERRUPTS_PER_PF)];
|
||||
|
||||
oct->msix_entries = kcalloc(oct->num_msix_irqs,
|
||||
sizeof(struct msix_entry),
|
||||
GFP_KERNEL);
|
||||
if (!oct->msix_entries) {
|
||||
dev_err(&oct->pci_dev->dev, "Memory Alloc failed...\n");
|
||||
kfree(oct->irq_name_storage);
|
||||
oct->irq_name_storage = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
msix_entries = (struct msix_entry *)oct->msix_entries;
|
||||
|
||||
/*Assumption is that pf msix vectors start from pf srn to pf to
|
||||
* trs and not from 0. if not change this code
|
||||
*/
|
||||
if (OCTEON_CN23XX_PF(oct)) {
|
||||
for (i = 0; i < oct->num_msix_irqs - 1; i++)
|
||||
msix_entries[i].entry =
|
||||
oct->sriov_info.pf_srn + i;
|
||||
|
||||
msix_entries[oct->num_msix_irqs - 1].entry =
|
||||
oct->sriov_info.trs;
|
||||
} else if (OCTEON_CN23XX_VF(oct)) {
|
||||
for (i = 0; i < oct->num_msix_irqs; i++)
|
||||
msix_entries[i].entry = i;
|
||||
}
|
||||
num_alloc_ioq_vectors = pci_enable_msix_range(
|
||||
oct->pci_dev, msix_entries,
|
||||
oct->num_msix_irqs,
|
||||
oct->num_msix_irqs);
|
||||
if (num_alloc_ioq_vectors < 0) {
|
||||
dev_err(&oct->pci_dev->dev, "unable to Allocate MSI-X interrupts\n");
|
||||
kfree(oct->msix_entries);
|
||||
oct->msix_entries = NULL;
|
||||
kfree(oct->irq_name_storage);
|
||||
oct->irq_name_storage = NULL;
|
||||
return num_alloc_ioq_vectors;
|
||||
}
|
||||
|
||||
dev_dbg(&oct->pci_dev->dev, "OCTEON: Enough MSI-X interrupts are allocated...\n");
|
||||
|
||||
num_ioq_vectors = oct->num_msix_irqs;
|
||||
/** For PF, there is one non-ioq interrupt handler */
|
||||
if (OCTEON_CN23XX_PF(oct)) {
|
||||
num_ioq_vectors -= 1;
|
||||
|
||||
snprintf(aux_irq_name, INTRNAMSIZ,
|
||||
"LiquidIO%u-pf%u-aux", oct->octeon_id,
|
||||
oct->pf_num);
|
||||
irqret = request_irq(
|
||||
msix_entries[num_ioq_vectors].vector,
|
||||
liquidio_legacy_intr_handler, 0,
|
||||
aux_irq_name, oct);
|
||||
if (irqret) {
|
||||
dev_err(&oct->pci_dev->dev,
|
||||
"Request_irq failed for MSIX interrupt Error: %d\n",
|
||||
irqret);
|
||||
pci_disable_msix(oct->pci_dev);
|
||||
kfree(oct->msix_entries);
|
||||
kfree(oct->irq_name_storage);
|
||||
oct->irq_name_storage = NULL;
|
||||
oct->msix_entries = NULL;
|
||||
return irqret;
|
||||
}
|
||||
}
|
||||
for (i = 0 ; i < num_ioq_vectors ; i++) {
|
||||
if (OCTEON_CN23XX_PF(oct))
|
||||
snprintf(&queue_irq_names[IRQ_NAME_OFF(i)],
|
||||
INTRNAMSIZ, "LiquidIO%u-pf%u-rxtx-%u",
|
||||
oct->octeon_id, oct->pf_num, i);
|
||||
|
||||
if (OCTEON_CN23XX_VF(oct))
|
||||
snprintf(&queue_irq_names[IRQ_NAME_OFF(i)],
|
||||
INTRNAMSIZ, "LiquidIO%u-vf%u-rxtx-%u",
|
||||
oct->octeon_id, oct->vf_num, i);
|
||||
|
||||
irqret = request_irq(msix_entries[i].vector,
|
||||
liquidio_msix_intr_handler, 0,
|
||||
&queue_irq_names[IRQ_NAME_OFF(i)],
|
||||
&oct->ioq_vector[i]);
|
||||
|
||||
if (irqret) {
|
||||
dev_err(&oct->pci_dev->dev,
|
||||
"Request_irq failed for MSIX interrupt Error: %d\n",
|
||||
irqret);
|
||||
/** Freeing the non-ioq irq vector here . */
|
||||
free_irq(msix_entries[num_ioq_vectors].vector,
|
||||
oct);
|
||||
|
||||
while (i) {
|
||||
i--;
|
||||
/** clearing affinity mask. */
|
||||
irq_set_affinity_hint(
|
||||
msix_entries[i].vector,
|
||||
NULL);
|
||||
free_irq(msix_entries[i].vector,
|
||||
&oct->ioq_vector[i]);
|
||||
}
|
||||
pci_disable_msix(oct->pci_dev);
|
||||
kfree(oct->msix_entries);
|
||||
kfree(oct->irq_name_storage);
|
||||
oct->irq_name_storage = NULL;
|
||||
oct->msix_entries = NULL;
|
||||
return irqret;
|
||||
}
|
||||
oct->ioq_vector[i].vector = msix_entries[i].vector;
|
||||
/* assign the cpu mask for this msix interrupt vector */
|
||||
irq_set_affinity_hint(msix_entries[i].vector,
|
||||
&oct->ioq_vector[i].affinity_mask
|
||||
);
|
||||
}
|
||||
dev_dbg(&oct->pci_dev->dev, "OCTEON[%d]: MSI-X enabled\n",
|
||||
oct->octeon_id);
|
||||
} else {
|
||||
err = pci_enable_msi(oct->pci_dev);
|
||||
if (err)
|
||||
dev_warn(&oct->pci_dev->dev, "Reverting to legacy interrupts. Error: %d\n",
|
||||
err);
|
||||
else
|
||||
oct->flags |= LIO_FLAG_MSI_ENABLED;
|
||||
|
||||
/* allocate storage for the names assigned to the irq */
|
||||
oct->irq_name_storage = kcalloc(1, INTRNAMSIZ, GFP_KERNEL);
|
||||
if (!oct->irq_name_storage)
|
||||
return -ENOMEM;
|
||||
|
||||
queue_irq_names = oct->irq_name_storage;
|
||||
|
||||
if (OCTEON_CN23XX_PF(oct))
|
||||
snprintf(&queue_irq_names[IRQ_NAME_OFF(0)], INTRNAMSIZ,
|
||||
"LiquidIO%u-pf%u-rxtx-%u",
|
||||
oct->octeon_id, oct->pf_num, 0);
|
||||
|
||||
if (OCTEON_CN23XX_VF(oct))
|
||||
snprintf(&queue_irq_names[IRQ_NAME_OFF(0)], INTRNAMSIZ,
|
||||
"LiquidIO%u-vf%u-rxtx-%u",
|
||||
oct->octeon_id, oct->vf_num, 0);
|
||||
|
||||
irqret = request_irq(oct->pci_dev->irq,
|
||||
liquidio_legacy_intr_handler,
|
||||
IRQF_SHARED,
|
||||
&queue_irq_names[IRQ_NAME_OFF(0)], oct);
|
||||
if (irqret) {
|
||||
if (oct->flags & LIO_FLAG_MSI_ENABLED)
|
||||
pci_disable_msi(oct->pci_dev);
|
||||
dev_err(&oct->pci_dev->dev, "Request IRQ failed with code: %d\n",
|
||||
irqret);
|
||||
kfree(oct->irq_name_storage);
|
||||
oct->irq_name_storage = NULL;
|
||||
return irqret;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -901,169 +901,6 @@ static inline void update_link_status(struct net_device *netdev,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Setup interrupt for octeon device
|
||||
* @param oct octeon device
|
||||
*
|
||||
* Enable interrupt in Octeon device as given in the PCI interrupt mask.
|
||||
*/
|
||||
static int octeon_setup_interrupt(struct octeon_device *oct)
|
||||
{
|
||||
int irqret, err;
|
||||
struct msix_entry *msix_entries;
|
||||
int i;
|
||||
int num_ioq_vectors;
|
||||
int num_alloc_ioq_vectors;
|
||||
char *queue_irq_names = NULL;
|
||||
char *aux_irq_name = NULL;
|
||||
|
||||
if (OCTEON_CN23XX_PF(oct) && oct->msix_on) {
|
||||
oct->num_msix_irqs = oct->sriov_info.num_pf_rings;
|
||||
/* one non ioq interrupt for handling sli_mac_pf_int_sum */
|
||||
oct->num_msix_irqs += 1;
|
||||
|
||||
/* allocate storage for the names assigned to each irq */
|
||||
oct->irq_name_storage =
|
||||
kcalloc((MAX_IOQ_INTERRUPTS_PER_PF + 1), INTRNAMSIZ,
|
||||
GFP_KERNEL);
|
||||
if (!oct->irq_name_storage) {
|
||||
dev_err(&oct->pci_dev->dev, "Irq name storage alloc failed...\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
queue_irq_names = oct->irq_name_storage;
|
||||
aux_irq_name = &queue_irq_names
|
||||
[IRQ_NAME_OFF(MAX_IOQ_INTERRUPTS_PER_PF)];
|
||||
|
||||
oct->msix_entries = kcalloc(
|
||||
oct->num_msix_irqs, sizeof(struct msix_entry), GFP_KERNEL);
|
||||
if (!oct->msix_entries) {
|
||||
dev_err(&oct->pci_dev->dev, "Memory Alloc failed...\n");
|
||||
kfree(oct->irq_name_storage);
|
||||
oct->irq_name_storage = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
msix_entries = (struct msix_entry *)oct->msix_entries;
|
||||
/*Assumption is that pf msix vectors start from pf srn to pf to
|
||||
* trs and not from 0. if not change this code
|
||||
*/
|
||||
for (i = 0; i < oct->num_msix_irqs - 1; i++)
|
||||
msix_entries[i].entry = oct->sriov_info.pf_srn + i;
|
||||
msix_entries[oct->num_msix_irqs - 1].entry =
|
||||
oct->sriov_info.trs;
|
||||
num_alloc_ioq_vectors = pci_enable_msix_range(
|
||||
oct->pci_dev, msix_entries,
|
||||
oct->num_msix_irqs,
|
||||
oct->num_msix_irqs);
|
||||
if (num_alloc_ioq_vectors < 0) {
|
||||
dev_err(&oct->pci_dev->dev, "unable to Allocate MSI-X interrupts\n");
|
||||
kfree(oct->msix_entries);
|
||||
oct->msix_entries = NULL;
|
||||
kfree(oct->irq_name_storage);
|
||||
oct->irq_name_storage = NULL;
|
||||
return num_alloc_ioq_vectors;
|
||||
}
|
||||
dev_dbg(&oct->pci_dev->dev, "OCTEON: Enough MSI-X interrupts are allocated...\n");
|
||||
|
||||
num_ioq_vectors = oct->num_msix_irqs;
|
||||
|
||||
/** For PF, there is one non-ioq interrupt handler */
|
||||
num_ioq_vectors -= 1;
|
||||
|
||||
snprintf(aux_irq_name, INTRNAMSIZ,
|
||||
"LiquidIO%u-pf%u-aux", oct->octeon_id, oct->pf_num);
|
||||
irqret = request_irq(msix_entries[num_ioq_vectors].vector,
|
||||
liquidio_legacy_intr_handler, 0,
|
||||
aux_irq_name, oct);
|
||||
if (irqret) {
|
||||
dev_err(&oct->pci_dev->dev,
|
||||
"OCTEON: Request_irq failed for MSIX interrupt Error: %d\n",
|
||||
irqret);
|
||||
pci_disable_msix(oct->pci_dev);
|
||||
kfree(oct->msix_entries);
|
||||
oct->msix_entries = NULL;
|
||||
kfree(oct->irq_name_storage);
|
||||
oct->irq_name_storage = NULL;
|
||||
return irqret;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_ioq_vectors; i++) {
|
||||
snprintf(&queue_irq_names[IRQ_NAME_OFF(i)], INTRNAMSIZ,
|
||||
"LiquidIO%u-pf%u-rxtx-%u",
|
||||
oct->octeon_id, oct->pf_num, i);
|
||||
|
||||
irqret = request_irq(msix_entries[i].vector,
|
||||
liquidio_msix_intr_handler, 0,
|
||||
&queue_irq_names[IRQ_NAME_OFF(i)],
|
||||
&oct->ioq_vector[i]);
|
||||
if (irqret) {
|
||||
dev_err(&oct->pci_dev->dev,
|
||||
"OCTEON: Request_irq failed for MSIX interrupt Error: %d\n",
|
||||
irqret);
|
||||
/** Freeing the non-ioq irq vector here . */
|
||||
free_irq(msix_entries[num_ioq_vectors].vector,
|
||||
oct);
|
||||
|
||||
while (i) {
|
||||
i--;
|
||||
/** clearing affinity mask. */
|
||||
irq_set_affinity_hint(
|
||||
msix_entries[i].vector, NULL);
|
||||
free_irq(msix_entries[i].vector,
|
||||
&oct->ioq_vector[i]);
|
||||
}
|
||||
pci_disable_msix(oct->pci_dev);
|
||||
kfree(oct->msix_entries);
|
||||
oct->msix_entries = NULL;
|
||||
kfree(oct->irq_name_storage);
|
||||
oct->irq_name_storage = NULL;
|
||||
return irqret;
|
||||
}
|
||||
oct->ioq_vector[i].vector = msix_entries[i].vector;
|
||||
/* assign the cpu mask for this msix interrupt vector */
|
||||
irq_set_affinity_hint(
|
||||
msix_entries[i].vector,
|
||||
(&oct->ioq_vector[i].affinity_mask));
|
||||
}
|
||||
dev_dbg(&oct->pci_dev->dev, "OCTEON[%d]: MSI-X enabled\n",
|
||||
oct->octeon_id);
|
||||
} else {
|
||||
err = pci_enable_msi(oct->pci_dev);
|
||||
if (err)
|
||||
dev_warn(&oct->pci_dev->dev, "Reverting to legacy interrupts. Error: %d\n",
|
||||
err);
|
||||
else
|
||||
oct->flags |= LIO_FLAG_MSI_ENABLED;
|
||||
|
||||
/* allocate storage for the names assigned to the irq */
|
||||
oct->irq_name_storage = kcalloc(1, INTRNAMSIZ, GFP_KERNEL);
|
||||
if (!oct->irq_name_storage)
|
||||
return -ENOMEM;
|
||||
|
||||
queue_irq_names = oct->irq_name_storage;
|
||||
|
||||
snprintf(&queue_irq_names[IRQ_NAME_OFF(0)], INTRNAMSIZ,
|
||||
"LiquidIO%u-pf%u-rxtx-%u",
|
||||
oct->octeon_id, oct->pf_num, 0);
|
||||
|
||||
irqret = request_irq(oct->pci_dev->irq,
|
||||
liquidio_legacy_intr_handler,
|
||||
IRQF_SHARED,
|
||||
&queue_irq_names[IRQ_NAME_OFF(0)], oct);
|
||||
if (irqret) {
|
||||
if (oct->flags & LIO_FLAG_MSI_ENABLED)
|
||||
pci_disable_msi(oct->pci_dev);
|
||||
dev_err(&oct->pci_dev->dev, "Request IRQ failed with code: %d\n",
|
||||
irqret);
|
||||
kfree(oct->irq_name_storage);
|
||||
oct->irq_name_storage = NULL;
|
||||
return irqret;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct octeon_device *get_other_octeon_device(struct octeon_device *oct)
|
||||
{
|
||||
struct octeon_device *other_oct;
|
||||
|
@ -642,104 +642,6 @@ static void update_link_status(struct net_device *netdev,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Setup interrupt for octeon device
|
||||
* @param oct octeon device
|
||||
*
|
||||
* Enable interrupt in Octeon device as given in the PCI interrupt mask.
|
||||
*/
|
||||
static int octeon_setup_interrupt(struct octeon_device *oct)
|
||||
{
|
||||
struct msix_entry *msix_entries;
|
||||
char *queue_irq_names = NULL;
|
||||
int num_alloc_ioq_vectors;
|
||||
int num_ioq_vectors;
|
||||
int irqret;
|
||||
int i;
|
||||
|
||||
if (oct->msix_on) {
|
||||
oct->num_msix_irqs = oct->sriov_info.rings_per_vf;
|
||||
|
||||
/* allocate storage for the names assigned to each irq */
|
||||
oct->irq_name_storage =
|
||||
kcalloc(MAX_IOQ_INTERRUPTS_PER_VF, INTRNAMSIZ,
|
||||
GFP_KERNEL);
|
||||
if (!oct->irq_name_storage) {
|
||||
dev_err(&oct->pci_dev->dev, "Irq name storage alloc failed...\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
queue_irq_names = oct->irq_name_storage;
|
||||
|
||||
oct->msix_entries = kcalloc(
|
||||
oct->num_msix_irqs, sizeof(struct msix_entry), GFP_KERNEL);
|
||||
if (!oct->msix_entries) {
|
||||
dev_err(&oct->pci_dev->dev, "Memory Alloc failed...\n");
|
||||
kfree(oct->irq_name_storage);
|
||||
oct->irq_name_storage = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
msix_entries = (struct msix_entry *)oct->msix_entries;
|
||||
|
||||
for (i = 0; i < oct->num_msix_irqs; i++)
|
||||
msix_entries[i].entry = i;
|
||||
num_alloc_ioq_vectors = pci_enable_msix_range(
|
||||
oct->pci_dev, msix_entries,
|
||||
oct->num_msix_irqs,
|
||||
oct->num_msix_irqs);
|
||||
if (num_alloc_ioq_vectors < 0) {
|
||||
dev_err(&oct->pci_dev->dev, "unable to Allocate MSI-X interrupts\n");
|
||||
kfree(oct->msix_entries);
|
||||
oct->msix_entries = NULL;
|
||||
kfree(oct->irq_name_storage);
|
||||
oct->irq_name_storage = NULL;
|
||||
return num_alloc_ioq_vectors;
|
||||
}
|
||||
dev_dbg(&oct->pci_dev->dev, "OCTEON: Enough MSI-X interrupts are allocated...\n");
|
||||
|
||||
num_ioq_vectors = oct->num_msix_irqs;
|
||||
|
||||
for (i = 0; i < num_ioq_vectors; i++) {
|
||||
snprintf(&queue_irq_names[IRQ_NAME_OFF(i)], INTRNAMSIZ,
|
||||
"LiquidIO%u-vf%u-rxtx-%u",
|
||||
oct->octeon_id, oct->vf_num, i);
|
||||
|
||||
irqret = request_irq(msix_entries[i].vector,
|
||||
liquidio_msix_intr_handler, 0,
|
||||
&queue_irq_names[IRQ_NAME_OFF(i)],
|
||||
&oct->ioq_vector[i]);
|
||||
if (irqret) {
|
||||
dev_err(&oct->pci_dev->dev,
|
||||
"OCTEON: Request_irq failed for MSIX interrupt Error: %d\n",
|
||||
irqret);
|
||||
|
||||
while (i) {
|
||||
i--;
|
||||
irq_set_affinity_hint(
|
||||
msix_entries[i].vector, NULL);
|
||||
free_irq(msix_entries[i].vector,
|
||||
&oct->ioq_vector[i]);
|
||||
}
|
||||
pci_disable_msix(oct->pci_dev);
|
||||
kfree(oct->msix_entries);
|
||||
oct->msix_entries = NULL;
|
||||
kfree(oct->irq_name_storage);
|
||||
oct->irq_name_storage = NULL;
|
||||
return irqret;
|
||||
}
|
||||
oct->ioq_vector[i].vector = msix_entries[i].vector;
|
||||
/* assign the cpu mask for this msix interrupt vector */
|
||||
irq_set_affinity_hint(
|
||||
msix_entries[i].vector,
|
||||
(&oct->ioq_vector[i].affinity_mask));
|
||||
}
|
||||
dev_dbg(&oct->pci_dev->dev,
|
||||
"OCTEON[%d]: MSI-X enabled\n", oct->octeon_id);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief PCI probe handler
|
||||
* @param pdev PCI device structure
|
||||
|
@ -172,8 +172,8 @@ int liquidio_setup_io_queues(struct octeon_device *octeon_dev, int ifidx);
|
||||
irqreturn_t liquidio_msix_intr_handler(int irq __attribute__((unused)),
|
||||
void *dev);
|
||||
|
||||
irqreturn_t liquidio_legacy_intr_handler(int irq __attribute__((unused)),
|
||||
void *dev);
|
||||
int octeon_setup_interrupt(struct octeon_device *oct);
|
||||
|
||||
/**
|
||||
* \brief Register ethtool operations
|
||||
* @param netdev pointer to network device
|
||||
|
Loading…
Reference in New Issue
Block a user