Commit 7c844599 authored by Scott Feldman's avatar Scott Feldman Committed by David S. Miller

enic: feature add: add ethtool -c/C support

Only rx_usec and tx_usec options for ethtool -C are settable as those
are the only settings that make sense to HW.  Adds driver reporting of
intr coalescing timer value in usec units rather than HW units.
Signed-off-by: default avatarVasanthy Kolluri <vkolluri@cisco.com>
Signed-off-by: default avatarScott Feldman <scofeldm@cisco.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent bd249622
...@@ -93,6 +93,8 @@ struct enic { ...@@ -93,6 +93,8 @@ struct enic {
unsigned int mc_count; unsigned int mc_count;
int csum_rx_enabled; int csum_rx_enabled;
u32 port_mtu; u32 port_mtu;
u32 rx_coalesce_usecs;
u32 tx_coalesce_usecs;
/* work queue cache line section */ /* work queue cache line section */
____cacheline_aligned struct vnic_wq wq[ENIC_WQ_MAX]; ____cacheline_aligned struct vnic_wq wq[ENIC_WQ_MAX];
......
...@@ -261,6 +261,62 @@ static void enic_set_msglevel(struct net_device *netdev, u32 value) ...@@ -261,6 +261,62 @@ static void enic_set_msglevel(struct net_device *netdev, u32 value)
enic->msg_enable = value; enic->msg_enable = value;
} }
static int enic_get_coalesce(struct net_device *netdev,
struct ethtool_coalesce *ecmd)
{
struct enic *enic = netdev_priv(netdev);
ecmd->tx_coalesce_usecs = enic->tx_coalesce_usecs;
ecmd->rx_coalesce_usecs = enic->rx_coalesce_usecs;
return 0;
}
static int enic_set_coalesce(struct net_device *netdev,
struct ethtool_coalesce *ecmd)
{
struct enic *enic = netdev_priv(netdev);
u32 tx_coalesce_usecs;
u32 rx_coalesce_usecs;
tx_coalesce_usecs = min_t(u32,
INTR_COALESCE_HW_TO_USEC(VNIC_INTR_TIMER_MAX),
ecmd->tx_coalesce_usecs);
rx_coalesce_usecs = min_t(u32,
INTR_COALESCE_HW_TO_USEC(VNIC_INTR_TIMER_MAX),
ecmd->rx_coalesce_usecs);
switch (vnic_dev_get_intr_mode(enic->vdev)) {
case VNIC_DEV_INTR_MODE_INTX:
if (tx_coalesce_usecs != rx_coalesce_usecs)
return -EINVAL;
vnic_intr_coalescing_timer_set(&enic->intr[ENIC_INTX_WQ_RQ],
INTR_COALESCE_USEC_TO_HW(tx_coalesce_usecs));
break;
case VNIC_DEV_INTR_MODE_MSI:
if (tx_coalesce_usecs != rx_coalesce_usecs)
return -EINVAL;
vnic_intr_coalescing_timer_set(&enic->intr[0],
INTR_COALESCE_USEC_TO_HW(tx_coalesce_usecs));
break;
case VNIC_DEV_INTR_MODE_MSIX:
vnic_intr_coalescing_timer_set(&enic->intr[ENIC_MSIX_WQ],
INTR_COALESCE_USEC_TO_HW(tx_coalesce_usecs));
vnic_intr_coalescing_timer_set(&enic->intr[ENIC_MSIX_RQ],
INTR_COALESCE_USEC_TO_HW(rx_coalesce_usecs));
break;
default:
break;
}
enic->tx_coalesce_usecs = tx_coalesce_usecs;
enic->rx_coalesce_usecs = rx_coalesce_usecs;
return 0;
}
static const struct ethtool_ops enic_ethtool_ops = { static const struct ethtool_ops enic_ethtool_ops = {
.get_settings = enic_get_settings, .get_settings = enic_get_settings,
.get_drvinfo = enic_get_drvinfo, .get_drvinfo = enic_get_drvinfo,
...@@ -278,6 +334,8 @@ static const struct ethtool_ops enic_ethtool_ops = { ...@@ -278,6 +334,8 @@ static const struct ethtool_ops enic_ethtool_ops = {
.set_sg = ethtool_op_set_sg, .set_sg = ethtool_op_set_sg,
.get_tso = ethtool_op_get_tso, .get_tso = ethtool_op_get_tso,
.set_tso = enic_set_tso, .set_tso = enic_set_tso,
.get_coalesce = enic_get_coalesce,
.set_coalesce = enic_set_coalesce,
.get_flags = ethtool_op_get_flags, .get_flags = ethtool_op_get_flags,
.set_flags = ethtool_op_set_flags, .set_flags = ethtool_op_set_flags,
}; };
...@@ -363,12 +421,12 @@ static void enic_mtu_check(struct enic *enic) ...@@ -363,12 +421,12 @@ static void enic_mtu_check(struct enic *enic)
u32 mtu = vnic_dev_mtu(enic->vdev); u32 mtu = vnic_dev_mtu(enic->vdev);
if (mtu && mtu != enic->port_mtu) { if (mtu && mtu != enic->port_mtu) {
enic->port_mtu = mtu;
if (mtu < enic->netdev->mtu) if (mtu < enic->netdev->mtu)
printk(KERN_WARNING PFX printk(KERN_WARNING PFX
"%s: interface MTU (%d) set higher " "%s: interface MTU (%d) set higher "
"than switch port MTU (%d)\n", "than switch port MTU (%d)\n",
enic->netdev->name, enic->netdev->mtu, mtu); enic->netdev->name, enic->netdev->mtu, mtu);
enic->port_mtu = mtu;
} }
} }
...@@ -1990,6 +2048,9 @@ static int __devinit enic_probe(struct pci_dev *pdev, ...@@ -1990,6 +2048,9 @@ static int __devinit enic_probe(struct pci_dev *pdev,
goto err_out_dev_deinit; goto err_out_dev_deinit;
} }
enic->tx_coalesce_usecs = enic->config.intr_timer_usec;
enic->rx_coalesce_usecs = enic->tx_coalesce_usecs;
netdev->netdev_ops = &enic_netdev_ops; netdev->netdev_ops = &enic_netdev_ops;
netdev->watchdog_timeo = 2 * HZ; netdev->watchdog_timeo = 2 * HZ;
netdev->ethtool_ops = &enic_ethtool_ops; netdev->ethtool_ops = &enic_ethtool_ops;
......
...@@ -66,9 +66,9 @@ int enic_get_vnic_config(struct enic *enic) ...@@ -66,9 +66,9 @@ int enic_get_vnic_config(struct enic *enic)
GET_CONFIG(wq_desc_count); GET_CONFIG(wq_desc_count);
GET_CONFIG(rq_desc_count); GET_CONFIG(rq_desc_count);
GET_CONFIG(mtu); GET_CONFIG(mtu);
GET_CONFIG(intr_timer);
GET_CONFIG(intr_timer_type); GET_CONFIG(intr_timer_type);
GET_CONFIG(intr_mode); GET_CONFIG(intr_mode);
GET_CONFIG(intr_timer_usec);
c->wq_desc_count = c->wq_desc_count =
min_t(u32, ENIC_MAX_WQ_DESCS, min_t(u32, ENIC_MAX_WQ_DESCS,
...@@ -88,15 +88,17 @@ int enic_get_vnic_config(struct enic *enic) ...@@ -88,15 +88,17 @@ int enic_get_vnic_config(struct enic *enic)
max_t(u16, ENIC_MIN_MTU, max_t(u16, ENIC_MIN_MTU,
c->mtu)); c->mtu));
c->intr_timer = min_t(u16, VNIC_INTR_TIMER_MAX, c->intr_timer); c->intr_timer_usec = min_t(u32,
INTR_COALESCE_HW_TO_USEC(VNIC_INTR_TIMER_MAX),
c->intr_timer_usec);
printk(KERN_INFO PFX "vNIC MAC addr %pM wq/rq %d/%d\n", printk(KERN_INFO PFX "vNIC MAC addr %pM wq/rq %d/%d\n",
enic->mac_addr, c->wq_desc_count, c->rq_desc_count); enic->mac_addr, c->wq_desc_count, c->rq_desc_count);
printk(KERN_INFO PFX "vNIC mtu %d csum tx/rx %d/%d tso/lro %d/%d " printk(KERN_INFO PFX "vNIC mtu %d csum tx/rx %d/%d tso/lro %d/%d "
"intr timer %d\n", "intr timer %d usec\n",
c->mtu, ENIC_SETTING(enic, TXCSUM), c->mtu, ENIC_SETTING(enic, TXCSUM),
ENIC_SETTING(enic, RXCSUM), ENIC_SETTING(enic, TSO), ENIC_SETTING(enic, RXCSUM), ENIC_SETTING(enic, TSO),
ENIC_SETTING(enic, LRO), c->intr_timer); ENIC_SETTING(enic, LRO), c->intr_timer_usec);
return 0; return 0;
} }
...@@ -303,7 +305,7 @@ void enic_init_vnic_resources(struct enic *enic) ...@@ -303,7 +305,7 @@ void enic_init_vnic_resources(struct enic *enic)
for (i = 0; i < enic->intr_count; i++) { for (i = 0; i < enic->intr_count; i++) {
vnic_intr_init(&enic->intr[i], vnic_intr_init(&enic->intr[i],
enic->config.intr_timer, INTR_COALESCE_USEC_TO_HW(enic->config.intr_timer_usec),
enic->config.intr_timer_type, enic->config.intr_timer_type,
mask_on_assertion); mask_on_assertion);
} }
......
...@@ -20,6 +20,10 @@ ...@@ -20,6 +20,10 @@
#ifndef _VNIC_ENIC_H_ #ifndef _VNIC_ENIC_H_
#define _VNIC_ENIC_H_ #define _VNIC_ENIC_H_
/* Hardware intr coalesce timer is in units of 1.5us */
#define INTR_COALESCE_USEC_TO_HW(usec) ((usec) * 2/3)
#define INTR_COALESCE_HW_TO_USEC(usec) ((usec) * 3/2)
/* Device-specific region: enet configuration */ /* Device-specific region: enet configuration */
struct vnic_enet_config { struct vnic_enet_config {
u32 flags; u32 flags;
...@@ -30,6 +34,7 @@ struct vnic_enet_config { ...@@ -30,6 +34,7 @@ struct vnic_enet_config {
u8 intr_timer_type; u8 intr_timer_type;
u8 intr_mode; u8 intr_mode;
char devname[16]; char devname[16];
u32 intr_timer_usec;
}; };
#define VENETF_TSO 0x1 /* TSO enabled */ #define VENETF_TSO 0x1 /* TSO enabled */
......
...@@ -50,12 +50,18 @@ int vnic_intr_alloc(struct vnic_dev *vdev, struct vnic_intr *intr, ...@@ -50,12 +50,18 @@ int vnic_intr_alloc(struct vnic_dev *vdev, struct vnic_intr *intr,
void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer, void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer,
unsigned int coalescing_type, unsigned int mask_on_assertion) unsigned int coalescing_type, unsigned int mask_on_assertion)
{ {
iowrite32(coalescing_timer, &intr->ctrl->coalescing_timer); vnic_intr_coalescing_timer_set(intr, coalescing_timer);
iowrite32(coalescing_type, &intr->ctrl->coalescing_type); iowrite32(coalescing_type, &intr->ctrl->coalescing_type);
iowrite32(mask_on_assertion, &intr->ctrl->mask_on_assertion); iowrite32(mask_on_assertion, &intr->ctrl->mask_on_assertion);
iowrite32(0, &intr->ctrl->int_credits); iowrite32(0, &intr->ctrl->int_credits);
} }
void vnic_intr_coalescing_timer_set(struct vnic_intr *intr,
unsigned int coalescing_timer)
{
iowrite32(coalescing_timer, &intr->ctrl->coalescing_timer);
}
void vnic_intr_clean(struct vnic_intr *intr) void vnic_intr_clean(struct vnic_intr *intr)
{ {
iowrite32(0, &intr->ctrl->int_credits); iowrite32(0, &intr->ctrl->int_credits);
......
...@@ -102,6 +102,8 @@ int vnic_intr_alloc(struct vnic_dev *vdev, struct vnic_intr *intr, ...@@ -102,6 +102,8 @@ int vnic_intr_alloc(struct vnic_dev *vdev, struct vnic_intr *intr,
unsigned int index); unsigned int index);
void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer, void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer,
unsigned int coalescing_type, unsigned int mask_on_assertion); unsigned int coalescing_type, unsigned int mask_on_assertion);
void vnic_intr_coalescing_timer_set(struct vnic_intr *intr,
unsigned int coalescing_timer);
void vnic_intr_clean(struct vnic_intr *intr); void vnic_intr_clean(struct vnic_intr *intr);
#endif /* _VNIC_INTR_H_ */ #endif /* _VNIC_INTR_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment