* Re: [PATCH] macvlan: lockless tx path
From: Eric Dumazet @ 2010-11-10 22:21 UTC (permalink / raw)
To: Ben Greear; +Cc: David Miller, Patrick McHardy, netdev
In-Reply-To: <4CDB1021.507@candelatech.com>
Le mercredi 10 novembre 2010 à 13:35 -0800, Ben Greear a écrit :
> So an application that must deal with wraps must poll at the minimal
> time interval for wrapping 32-bit counters at whatever speed, or it
> must pay attention to the driver to somehow know that this magic driver
> can *really* do 64-bit stats properly?
>
Are you aware that you speak of something that is not specified at all
in linux ?
Frequency of polling is not part of any RFC. This usually is tunable in
the _application_. Some people sample stats every 5 minutes, some sample
every second, and hit the "xxx driver updates its stats every two
seconds, this sucks"
I wrote SNMP apps based on /proc/net/dev and all just work, with any
versions, any driver. Of course, some of them broke 6 years ago because
they were 32bit legacy application, running on a 64bit kernel. I never
asked David to change /proc/net/dev to cap counters to 32bit.
When 128bit cpu come, some userland changes are needed to parse 128bit
numbers.
In anycase, apps dont have to know a particular driver provides 64bit or
32bit counter. Only choice for them is to automatically detect the
wraparound, because they fetch a STRING, not a Counter32 or Counter64
This works for all drivers, legacy, new, Intel or whatever. If a driver
changes from 32 to 64, nothing special happens in /proc/net/dev.
RRD for example handles this just fine.
> Please note that just because a counter is less than the previous read,
> that doesn't by itself tell us if it wrapped once or twice. And, if we
> don't know at which number of bits it wraps, then we don't know how many
> to add even if we are certain it wrapped only once.
>
I repeat : Nothing in /proc/net/dev can tell you when a counter will
wrap (the counter width).
You also need to use the correct polling frequency, depending on max
speed. It was already the case with 32bit counters, 64bit ones only gave
some extra range.
> In general, I want to treat eth0 the same as eth5, and not worry that one
> is 10/100 realtek and the other a 10G Intel.
>
> If netlink reports stats64, then those should only wrap at 64 bits,
> and if it reports stats32, then wrap at 32-bits.
>
I believe you are mistaken. We provide stats64 for all drivers, even
32bit legacy ones. rtnetlink has no way to report counter widths,
because nobody cared.
^ permalink raw reply
* Re: [PATCH 2.6.36-rc8] net-next: Add multiqueue support to vmxnet3 v2driver
From: Shreyas Bhatewara @ 2010-11-10 22:37 UTC (permalink / raw)
To: David Miller
Cc: bhutchings@solarflare.com, shemminger@vyatta.com,
netdev@vger.kernel.org, pv-drivers@vmware.com,
linux-kernel@vger.kernel.org
In-Reply-To: <alpine.LRH.2.00.1011011522020.12306@sbhatewara-dev1.eng.vmware.com>
On Mon, 1 Nov 2010, Shreyas Bhatewara wrote:
David/Stephen,
Any word about this patch ? To list out the changes made to the patch
since last time :
- Added ethtool handlers for configuring RSS table and getting # rx queues
- Removed module parameters which were not strictly required. Eg. Those required
for the above configuration
- Introduced module parameter to enable/disable multiqueue capability of
the driver
Thanks.
Shreyas
Reviewed-by: Bhavesh Davda <bhavesh@vmware.com>
>
>
> Add multiqueue support to vmxnet3 driver
>
> This change adds Multiqueue and thus receive side scaling support
> to vmxnet3 device driver. Number of rx queues is limited to 1 in cases
> where
> - MSI is not configured or
> - One MSIx vector is not available per rx queue
>
> By default multiqueue capability is turned off and hence only 1 tx and 1 rx
> queue will be initialized. enable_mq module param should be set to
> configure number of tx and rx queues equal to number of online CPUs. A
> maximum of 8 tx/rx queues are allowed for any adapter.
>
> Signed-off-by: Shreyas Bhatewara <sbhatewara@vmware.com>
>
> ---
>
> 2nd revision of the patch.
>
> In this revision, module params which are not strictly required have been
> removed and ethtool callback handlers have been implemented instead.
> Handlers to provide # rx queues and to get/set RSS indirection table are added.
> Information like Number of queues and how they share irqs is required at
> driver attach time. Adding ethtool interfaces cannot help in this regards.
> Hence two module params have been introduced : enable_mq (to configure if
> multiple queues should be used) and irq_share_mode to configure the way in
> which irqs will be shared among queues.
>
>
> diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
> index 3f60e0e..3ed4be6 100644
> --- a/drivers/net/vmxnet3/vmxnet3_drv.c
> +++ b/drivers/net/vmxnet3/vmxnet3_drv.c
> @@ -44,6 +44,26 @@ MODULE_DEVICE_TABLE(pci, vmxnet3_pciid_table);
>
> static atomic_t devices_found;
>
> +#define VMXNET3_MAX_DEVICES 10
> +static int enable_mq[VMXNET3_MAX_DEVICES + 1] = {
> + [0 ... VMXNET3_MAX_DEVICES] = 0 };
> +static int irq_share_mode[VMXNET3_MAX_DEVICES + 1] = {
> + [0 ... VMXNET3_MAX_DEVICES] = VMXNET3_INTR_BUDDYSHARE };
> +
> +static unsigned int num_adapters;
> +module_param_array(irq_share_mode, int, &num_adapters, 0400);
> +MODULE_PARM_DESC(irq_share_mode, "Comma separated list of ints, configuring "
> + "mode in which irqs should be shared by tx and rx queues. When"
> + " set to 0, no irqs are shared, each tx and rx queue allocate"
> + " and use a separate irq. Set to 1, all tx queues share an irq"
> + ". Set to 2, corresponding tx and rx queues share an irq."
> + " Default is 2.");
> +module_param_array(enable_mq, int, &num_adapters, 0400);
> +MODULE_PARM_DESC(enable_mq, "Comma separated list of integers, one for each "
> + "adapter. When set to a non-zero value, multiqueue will be "
> + "enabled and number of tx and rx queues will be same as number"
> + " of CPUs online. number of queues will be 1 otherwise. "
> + "Default is 0 - multiqueue disabled.");
>
> /*
> * Enable/Disable the given intr
> @@ -107,7 +127,7 @@ static void
> vmxnet3_tq_start(struct vmxnet3_tx_queue *tq, struct vmxnet3_adapter *adapter)
> {
> tq->stopped = false;
> - netif_start_queue(adapter->netdev);
> + netif_start_subqueue(adapter->netdev, tq - adapter->tx_queue);
> }
>
>
> @@ -115,7 +135,7 @@ static void
> vmxnet3_tq_wake(struct vmxnet3_tx_queue *tq, struct vmxnet3_adapter *adapter)
> {
> tq->stopped = false;
> - netif_wake_queue(adapter->netdev);
> + netif_wake_subqueue(adapter->netdev, (tq - adapter->tx_queue));
> }
>
>
> @@ -124,7 +144,7 @@ vmxnet3_tq_stop(struct vmxnet3_tx_queue *tq, struct vmxnet3_adapter *adapter)
> {
> tq->stopped = true;
> tq->num_stop++;
> - netif_stop_queue(adapter->netdev);
> + netif_stop_subqueue(adapter->netdev, (tq - adapter->tx_queue));
> }
>
>
> @@ -135,6 +155,7 @@ static void
> vmxnet3_check_link(struct vmxnet3_adapter *adapter, bool affectTxQueue)
> {
> u32 ret;
> + int i;
>
> VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_LINK);
> ret = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_CMD);
> @@ -145,22 +166,28 @@ vmxnet3_check_link(struct vmxnet3_adapter *adapter, bool affectTxQueue)
> if (!netif_carrier_ok(adapter->netdev))
> netif_carrier_on(adapter->netdev);
>
> - if (affectTxQueue)
> - vmxnet3_tq_start(&adapter->tx_queue, adapter);
> + if (affectTxQueue) {
> + for (i = 0; i < adapter->num_tx_queues; i++)
> + vmxnet3_tq_start(&adapter->tx_queue[i],
> + adapter);
> + }
> } else {
> printk(KERN_INFO "%s: NIC Link is Down\n",
> adapter->netdev->name);
> if (netif_carrier_ok(adapter->netdev))
> netif_carrier_off(adapter->netdev);
>
> - if (affectTxQueue)
> - vmxnet3_tq_stop(&adapter->tx_queue, adapter);
> + if (affectTxQueue) {
> + for (i = 0; i < adapter->num_tx_queues; i++)
> + vmxnet3_tq_stop(&adapter->tx_queue[i], adapter);
> + }
> }
> }
>
> static void
> vmxnet3_process_events(struct vmxnet3_adapter *adapter)
> {
> + int i;
> u32 events = le32_to_cpu(adapter->shared->ecr);
> if (!events)
> return;
> @@ -176,16 +203,18 @@ vmxnet3_process_events(struct vmxnet3_adapter *adapter)
> VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
> VMXNET3_CMD_GET_QUEUE_STATUS);
>
> - if (adapter->tqd_start->status.stopped) {
> - printk(KERN_ERR "%s: tq error 0x%x\n",
> - adapter->netdev->name,
> - le32_to_cpu(adapter->tqd_start->status.error));
> - }
> - if (adapter->rqd_start->status.stopped) {
> - printk(KERN_ERR "%s: rq error 0x%x\n",
> - adapter->netdev->name,
> - adapter->rqd_start->status.error);
> - }
> + for (i = 0; i < adapter->num_tx_queues; i++)
> + if (adapter->tqd_start[i].status.stopped)
> + dev_dbg(&adapter->netdev->dev,
> + "%s: tq[%d] error 0x%x\n",
> + adapter->netdev->name, i, le32_to_cpu(
> + adapter->tqd_start[i].status.error));
> + for (i = 0; i < adapter->num_rx_queues; i++)
> + if (adapter->rqd_start[i].status.stopped)
> + dev_dbg(&adapter->netdev->dev,
> + "%s: rq[%d] error 0x%x\n",
> + adapter->netdev->name, i,
> + adapter->rqd_start[i].status.error);
>
> schedule_work(&adapter->work);
> }
> @@ -410,7 +439,7 @@ vmxnet3_tq_cleanup(struct vmxnet3_tx_queue *tq,
> }
>
>
> -void
> +static void
> vmxnet3_tq_destroy(struct vmxnet3_tx_queue *tq,
> struct vmxnet3_adapter *adapter)
> {
> @@ -437,6 +466,17 @@ vmxnet3_tq_destroy(struct vmxnet3_tx_queue *tq,
> }
>
>
> +/* Destroy all tx queues */
> +void
> +vmxnet3_tq_destroy_all(struct vmxnet3_adapter *adapter)
> +{
> + int i;
> +
> + for (i = 0; i < adapter->num_tx_queues; i++)
> + vmxnet3_tq_destroy(&adapter->tx_queue[i], adapter);
> +}
> +
> +
> static void
> vmxnet3_tq_init(struct vmxnet3_tx_queue *tq,
> struct vmxnet3_adapter *adapter)
> @@ -518,6 +558,14 @@ err:
> return -ENOMEM;
> }
>
> +static void
> +vmxnet3_tq_cleanup_all(struct vmxnet3_adapter *adapter)
> +{
> + int i;
> +
> + for (i = 0; i < adapter->num_tx_queues; i++)
> + vmxnet3_tq_cleanup(&adapter->tx_queue[i], adapter);
> +}
>
> /*
> * starting from ring->next2fill, allocate rx buffers for the given ring
> @@ -732,6 +780,17 @@ vmxnet3_map_pkt(struct sk_buff *skb, struct vmxnet3_tx_ctx *ctx,
> }
>
>
> +/* Init all tx queues */
> +static void
> +vmxnet3_tq_init_all(struct vmxnet3_adapter *adapter)
> +{
> + int i;
> +
> + for (i = 0; i < adapter->num_tx_queues; i++)
> + vmxnet3_tq_init(&adapter->tx_queue[i], adapter);
> +}
> +
> +
> /*
> * parse and copy relevant protocol headers:
> * For a tso pkt, relevant headers are L2/3/4 including options
> @@ -1000,8 +1059,8 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
> if (le32_to_cpu(tq->shared->txNumDeferred) >=
> le32_to_cpu(tq->shared->txThreshold)) {
> tq->shared->txNumDeferred = 0;
> - VMXNET3_WRITE_BAR0_REG(adapter, VMXNET3_REG_TXPROD,
> - tq->tx_ring.next2fill);
> + VMXNET3_WRITE_BAR0_REG(adapter, (VMXNET3_REG_TXPROD +
> + tq->qid * 8), tq->tx_ring.next2fill);
> }
>
> return NETDEV_TX_OK;
> @@ -1020,7 +1079,10 @@ vmxnet3_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
> {
> struct vmxnet3_adapter *adapter = netdev_priv(netdev);
>
> - return vmxnet3_tq_xmit(skb, &adapter->tx_queue, adapter, netdev);
> + BUG_ON(skb->queue_mapping > adapter->num_tx_queues);
> + return vmxnet3_tq_xmit(skb,
> + &adapter->tx_queue[skb->queue_mapping],
> + adapter, netdev);
> }
>
>
> @@ -1106,9 +1168,9 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
> break;
> }
> num_rxd++;
> -
> + BUG_ON(rcd->rqID != rq->qid && rcd->rqID != rq->qid2);
> idx = rcd->rxdIdx;
> - ring_idx = rcd->rqID == rq->qid ? 0 : 1;
> + ring_idx = rcd->rqID < adapter->num_rx_queues ? 0 : 1;
> vmxnet3_getRxDesc(rxd, &rq->rx_ring[ring_idx].base[idx].rxd,
> &rxCmdDesc);
> rbi = rq->buf_info[ring_idx] + idx;
> @@ -1260,6 +1322,16 @@ vmxnet3_rq_cleanup(struct vmxnet3_rx_queue *rq,
> }
>
>
> +static void
> +vmxnet3_rq_cleanup_all(struct vmxnet3_adapter *adapter)
> +{
> + int i;
> +
> + for (i = 0; i < adapter->num_rx_queues; i++)
> + vmxnet3_rq_cleanup(&adapter->rx_queue[i], adapter);
> +}
> +
> +
> void vmxnet3_rq_destroy(struct vmxnet3_rx_queue *rq,
> struct vmxnet3_adapter *adapter)
> {
> @@ -1351,6 +1423,25 @@ vmxnet3_rq_init(struct vmxnet3_rx_queue *rq,
>
>
> static int
> +vmxnet3_rq_init_all(struct vmxnet3_adapter *adapter)
> +{
> + int i, err = 0;
> +
> + for (i = 0; i < adapter->num_rx_queues; i++) {
> + err = vmxnet3_rq_init(&adapter->rx_queue[i], adapter);
> + if (unlikely(err)) {
> + dev_err(&adapter->netdev->dev, "%s: failed to "
> + "initialize rx queue%i\n",
> + adapter->netdev->name, i);
> + break;
> + }
> + }
> + return err;
> +
> +}
> +
> +
> +static int
> vmxnet3_rq_create(struct vmxnet3_rx_queue *rq, struct vmxnet3_adapter *adapter)
> {
> int i;
> @@ -1398,32 +1489,176 @@ err:
>
>
> static int
> +vmxnet3_rq_create_all(struct vmxnet3_adapter *adapter)
> +{
> + int i, err = 0;
> +
> + for (i = 0; i < adapter->num_rx_queues; i++) {
> + err = vmxnet3_rq_create(&adapter->rx_queue[i], adapter);
> + if (unlikely(err)) {
> + dev_err(&adapter->netdev->dev,
> + "%s: failed to create rx queue%i\n",
> + adapter->netdev->name, i);
> + goto err_out;
> + }
> + }
> + return err;
> +err_out:
> + vmxnet3_rq_destroy_all(adapter);
> + return err;
> +
> +}
> +
> +/* Multiple queue aware polling function for tx and rx */
> +
> +static int
> vmxnet3_do_poll(struct vmxnet3_adapter *adapter, int budget)
> {
> + int rcd_done = 0, i;
> if (unlikely(adapter->shared->ecr))
> vmxnet3_process_events(adapter);
> + for (i = 0; i < adapter->num_tx_queues; i++)
> + vmxnet3_tq_tx_complete(&adapter->tx_queue[i], adapter);
>
> - vmxnet3_tq_tx_complete(&adapter->tx_queue, adapter);
> - return vmxnet3_rq_rx_complete(&adapter->rx_queue, adapter, budget);
> + for (i = 0; i < adapter->num_rx_queues; i++)
> + rcd_done += vmxnet3_rq_rx_complete(&adapter->rx_queue[i],
> + adapter, budget);
> + return rcd_done;
> }
>
>
> static int
> vmxnet3_poll(struct napi_struct *napi, int budget)
> {
> - struct vmxnet3_adapter *adapter = container_of(napi,
> - struct vmxnet3_adapter, napi);
> + struct vmxnet3_rx_queue *rx_queue = container_of(napi,
> + struct vmxnet3_rx_queue, napi);
> int rxd_done;
>
> - rxd_done = vmxnet3_do_poll(adapter, budget);
> + rxd_done = vmxnet3_do_poll(rx_queue->adapter, budget);
>
> if (rxd_done < budget) {
> napi_complete(napi);
> - vmxnet3_enable_intr(adapter, 0);
> + vmxnet3_enable_all_intrs(rx_queue->adapter);
> }
> return rxd_done;
> }
>
> +/*
> + * NAPI polling function for MSI-X mode with multiple Rx queues
> + * Returns the # of the NAPI credit consumed (# of rx descriptors processed)
> + */
> +
> +static int
> +vmxnet3_poll_rx_only(struct napi_struct *napi, int budget)
> +{
> + struct vmxnet3_rx_queue *rq = container_of(napi,
> + struct vmxnet3_rx_queue, napi);
> + struct vmxnet3_adapter *adapter = rq->adapter;
> + int rxd_done;
> +
> + /* When sharing interrupt with corresponding tx queue, process
> + * tx completions in that queue as well
> + */
> + if (adapter->share_intr == VMXNET3_INTR_BUDDYSHARE) {
> + struct vmxnet3_tx_queue *tq =
> + &adapter->tx_queue[rq - adapter->rx_queue];
> + vmxnet3_tq_tx_complete(tq, adapter);
> + }
> +
> + rxd_done = vmxnet3_rq_rx_complete(rq, adapter, budget);
> +
> + if (rxd_done < budget) {
> + napi_complete(napi);
> + vmxnet3_enable_intr(adapter, rq->comp_ring.intr_idx);
> + }
> + return rxd_done;
> +}
> +
> +
> +#ifdef CONFIG_PCI_MSI
> +
> +/*
> + * Handle completion interrupts on tx queues
> + * Returns whether or not the intr is handled
> + */
> +
> +static irqreturn_t
> +vmxnet3_msix_tx(int irq, void *data)
> +{
> + struct vmxnet3_tx_queue *tq = data;
> + struct vmxnet3_adapter *adapter = tq->adapter;
> +
> + if (adapter->intr.mask_mode == VMXNET3_IMM_ACTIVE)
> + vmxnet3_disable_intr(adapter, tq->comp_ring.intr_idx);
> +
> + /* Handle the case where only one irq is allocate for all tx queues */
> + if (adapter->share_intr == VMXNET3_INTR_TXSHARE) {
> + int i;
> + for (i = 0; i < adapter->num_tx_queues; i++) {
> + struct vmxnet3_tx_queue *txq = &adapter->tx_queue[i];
> + vmxnet3_tq_tx_complete(txq, adapter);
> + }
> + } else {
> + vmxnet3_tq_tx_complete(tq, adapter);
> + }
> + vmxnet3_enable_intr(adapter, tq->comp_ring.intr_idx);
> +
> + return IRQ_HANDLED;
> +}
> +
> +
> +/*
> + * Handle completion interrupts on rx queues. Returns whether or not the
> + * intr is handled
> + */
> +
> +static irqreturn_t
> +vmxnet3_msix_rx(int irq, void *data)
> +{
> + struct vmxnet3_rx_queue *rq = data;
> + struct vmxnet3_adapter *adapter = rq->adapter;
> +
> + /* disable intr if needed */
> + if (adapter->intr.mask_mode == VMXNET3_IMM_ACTIVE)
> + vmxnet3_disable_intr(adapter, rq->comp_ring.intr_idx);
> + napi_schedule(&rq->napi);
> +
> + return IRQ_HANDLED;
> +}
> +
> +/*
> + *----------------------------------------------------------------------------
> + *
> + * vmxnet3_msix_event --
> + *
> + * vmxnet3 msix event intr handler
> + *
> + * Result:
> + * whether or not the intr is handled
> + *
> + *----------------------------------------------------------------------------
> + */
> +
> +static irqreturn_t
> +vmxnet3_msix_event(int irq, void *data)
> +{
> + struct net_device *dev = data;
> + struct vmxnet3_adapter *adapter = netdev_priv(dev);
> +
> + /* disable intr if needed */
> + if (adapter->intr.mask_mode == VMXNET3_IMM_ACTIVE)
> + vmxnet3_disable_intr(adapter, adapter->intr.event_intr_idx);
> +
> + if (adapter->shared->ecr)
> + vmxnet3_process_events(adapter);
> +
> + vmxnet3_enable_intr(adapter, adapter->intr.event_intr_idx);
> +
> + return IRQ_HANDLED;
> +}
> +
> +#endif /* CONFIG_PCI_MSI */
> +
>
> /* Interrupt handler for vmxnet3 */
> static irqreturn_t
> @@ -1432,7 +1667,7 @@ vmxnet3_intr(int irq, void *dev_id)
> struct net_device *dev = dev_id;
> struct vmxnet3_adapter *adapter = netdev_priv(dev);
>
> - if (unlikely(adapter->intr.type == VMXNET3_IT_INTX)) {
> + if (adapter->intr.type == VMXNET3_IT_INTX) {
> u32 icr = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_ICR);
> if (unlikely(icr == 0))
> /* not ours */
> @@ -1442,77 +1677,136 @@ vmxnet3_intr(int irq, void *dev_id)
>
> /* disable intr if needed */
> if (adapter->intr.mask_mode == VMXNET3_IMM_ACTIVE)
> - vmxnet3_disable_intr(adapter, 0);
> + vmxnet3_disable_all_intrs(adapter);
>
> - napi_schedule(&adapter->napi);
> + napi_schedule(&adapter->rx_queue[0].napi);
>
> return IRQ_HANDLED;
> }
>
> #ifdef CONFIG_NET_POLL_CONTROLLER
>
> -
> /* netpoll callback. */
> static void
> vmxnet3_netpoll(struct net_device *netdev)
> {
> struct vmxnet3_adapter *adapter = netdev_priv(netdev);
> - int irq;
>
> -#ifdef CONFIG_PCI_MSI
> - if (adapter->intr.type == VMXNET3_IT_MSIX)
> - irq = adapter->intr.msix_entries[0].vector;
> - else
> -#endif
> - irq = adapter->pdev->irq;
> + if (adapter->intr.mask_mode == VMXNET3_IMM_ACTIVE)
> + vmxnet3_disable_all_intrs(adapter);
> +
> + vmxnet3_do_poll(adapter, adapter->rx_queue[0].rx_ring[0].size);
> + vmxnet3_enable_all_intrs(adapter);
>
> - disable_irq(irq);
> - vmxnet3_intr(irq, netdev);
> - enable_irq(irq);
> }
> -#endif
> +#endif /* CONFIG_NET_POLL_CONTROLLER */
>
> static int
> vmxnet3_request_irqs(struct vmxnet3_adapter *adapter)
> {
> - int err;
> + struct vmxnet3_intr *intr = &adapter->intr;
> + int err = 0, i;
> + int vector = 0;
>
> #ifdef CONFIG_PCI_MSI
> if (adapter->intr.type == VMXNET3_IT_MSIX) {
> - /* we only use 1 MSI-X vector */
> - err = request_irq(adapter->intr.msix_entries[0].vector,
> - vmxnet3_intr, 0, adapter->netdev->name,
> - adapter->netdev);
> - } else if (adapter->intr.type == VMXNET3_IT_MSI) {
> + for (i = 0; i < adapter->num_tx_queues; i++) {
> + sprintf(adapter->tx_queue[i].name, "%s:v%d-%s",
> + adapter->netdev->name, vector, "Tx");
> + if (adapter->share_intr != VMXNET3_INTR_BUDDYSHARE)
> + err = request_irq(
> + intr->msix_entries[vector].vector,
> + vmxnet3_msix_tx, 0,
> + adapter->tx_queue[i].name,
> + &adapter->tx_queue[i]);
> + if (err) {
> + dev_err(&adapter->netdev->dev,
> + "Failed to request irq for MSIX, %s, "
> + "error %d\n",
> + adapter->tx_queue[i].name, err);
> + return err;
> + }
> +
> + /* Handle the case where only 1 MSIx was allocated for
> + * all tx queues */
> + if (adapter->share_intr == VMXNET3_INTR_TXSHARE) {
> + for (; i < adapter->num_tx_queues; i++)
> + adapter->tx_queue[i].comp_ring.intr_idx
> + = vector;
> + vector++;
> + break;
> + } else {
> + adapter->tx_queue[i].comp_ring.intr_idx
> + = vector++;
> + }
> + }
> + if (adapter->share_intr == VMXNET3_INTR_BUDDYSHARE)
> + vector = 0;
> +
> + for (i = 0; i < adapter->num_rx_queues; i++) {
> + sprintf(adapter->rx_queue[i].name, "%s:v%d-%s",
> + adapter->netdev->name, vector, "Rx");
> + err = request_irq(intr->msix_entries[vector].vector,
> + vmxnet3_msix_rx, 0,
> + adapter->rx_queue[i].name,
> + &(adapter->rx_queue[i]));
> + if (err) {
> + printk(KERN_ERR "Failed to request irq for MSIX"
> + ", %s, error %d\n",
> + adapter->rx_queue[i].name, err);
> + return err;
> + }
> +
> + adapter->rx_queue[i].comp_ring.intr_idx = vector++;
> + }
> +
> + sprintf(intr->event_msi_vector_name, "%s:v%d-event",
> + adapter->netdev->name, vector);
> + err = request_irq(intr->msix_entries[vector].vector,
> + vmxnet3_msix_event, 0,
> + intr->event_msi_vector_name, adapter->netdev);
> + intr->event_intr_idx = vector;
> +
> + } else if (intr->type == VMXNET3_IT_MSI) {
> + adapter->num_rx_queues = 1;
> err = request_irq(adapter->pdev->irq, vmxnet3_intr, 0,
> adapter->netdev->name, adapter->netdev);
> - } else
> + } else {
> #endif
> - {
> + adapter->num_rx_queues = 1;
> err = request_irq(adapter->pdev->irq, vmxnet3_intr,
> IRQF_SHARED, adapter->netdev->name,
> adapter->netdev);
> +#ifdef CONFIG_PCI_MSI
> }
> -
> - if (err)
> +#endif
> + intr->num_intrs = vector + 1;
> + if (err) {
> printk(KERN_ERR "Failed to request irq %s (intr type:%d), error"
> - ":%d\n", adapter->netdev->name, adapter->intr.type, err);
> + ":%d\n", adapter->netdev->name, intr->type, err);
> + } else {
> + /* Number of rx queues will not change after this */
> + for (i = 0; i < adapter->num_rx_queues; i++) {
> + struct vmxnet3_rx_queue *rq = &adapter->rx_queue[i];
> + rq->qid = i;
> + rq->qid2 = i + adapter->num_rx_queues;
> + }
>
>
> - if (!err) {
> - int i;
> - /* init our intr settings */
> - for (i = 0; i < adapter->intr.num_intrs; i++)
> - adapter->intr.mod_levels[i] = UPT1_IML_ADAPTIVE;
>
> - /* next setup intr index for all intr sources */
> - adapter->tx_queue.comp_ring.intr_idx = 0;
> - adapter->rx_queue.comp_ring.intr_idx = 0;
> - adapter->intr.event_intr_idx = 0;
> + /* init our intr settings */
> + for (i = 0; i < intr->num_intrs; i++)
> + intr->mod_levels[i] = UPT1_IML_ADAPTIVE;
> + if (adapter->intr.type != VMXNET3_IT_MSIX) {
> + adapter->intr.event_intr_idx = 0;
> + for (i = 0; i < adapter->num_tx_queues; i++)
> + adapter->tx_queue[i].comp_ring.intr_idx = 0;
> + adapter->rx_queue[0].comp_ring.intr_idx = 0;
> + }
>
> printk(KERN_INFO "%s: intr type %u, mode %u, %u vectors "
> - "allocated\n", adapter->netdev->name, adapter->intr.type,
> - adapter->intr.mask_mode, adapter->intr.num_intrs);
> + "allocated\n", adapter->netdev->name, intr->type,
> + intr->mask_mode, intr->num_intrs);
> }
>
> return err;
> @@ -1522,18 +1816,32 @@ vmxnet3_request_irqs(struct vmxnet3_adapter *adapter)
> static void
> vmxnet3_free_irqs(struct vmxnet3_adapter *adapter)
> {
> - BUG_ON(adapter->intr.type == VMXNET3_IT_AUTO ||
> - adapter->intr.num_intrs <= 0);
> + struct vmxnet3_intr *intr = &adapter->intr;
> + BUG_ON(intr->type == VMXNET3_IT_AUTO || intr->num_intrs <= 0);
>
> - switch (adapter->intr.type) {
> + switch (intr->type) {
> #ifdef CONFIG_PCI_MSI
> case VMXNET3_IT_MSIX:
> {
> - int i;
> + int i, vector = 0;
> +
> + if (adapter->share_intr != VMXNET3_INTR_BUDDYSHARE) {
> + for (i = 0; i < adapter->num_tx_queues; i++) {
> + free_irq(intr->msix_entries[vector++].vector,
> + &(adapter->tx_queue[i]));
> + if (adapter->share_intr == VMXNET3_INTR_TXSHARE)
> + break;
> + }
> + }
> +
> + for (i = 0; i < adapter->num_rx_queues; i++) {
> + free_irq(intr->msix_entries[vector++].vector,
> + &(adapter->rx_queue[i]));
> + }
>
> - for (i = 0; i < adapter->intr.num_intrs; i++)
> - free_irq(adapter->intr.msix_entries[i].vector,
> - adapter->netdev);
> + free_irq(intr->msix_entries[vector].vector,
> + adapter->netdev);
> + BUG_ON(vector >= intr->num_intrs);
> break;
> }
> #endif
> @@ -1729,6 +2037,15 @@ vmxnet3_set_mc(struct net_device *netdev)
> kfree(new_table);
> }
>
> +void
> +vmxnet3_rq_destroy_all(struct vmxnet3_adapter *adapter)
> +{
> + int i;
> +
> + for (i = 0; i < adapter->num_rx_queues; i++)
> + vmxnet3_rq_destroy(&adapter->rx_queue[i], adapter);
> +}
> +
>
> /*
> * Set up driver_shared based on settings in adapter.
> @@ -1776,40 +2093,72 @@ vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter)
> devRead->misc.mtu = cpu_to_le32(adapter->netdev->mtu);
> devRead->misc.queueDescPA = cpu_to_le64(adapter->queue_desc_pa);
> devRead->misc.queueDescLen = cpu_to_le32(
> - sizeof(struct Vmxnet3_TxQueueDesc) +
> - sizeof(struct Vmxnet3_RxQueueDesc));
> + adapter->num_tx_queues * sizeof(struct Vmxnet3_TxQueueDesc) +
> + adapter->num_rx_queues * sizeof(struct Vmxnet3_RxQueueDesc));
>
> /* tx queue settings */
> - BUG_ON(adapter->tx_queue.tx_ring.base == NULL);
> -
> - devRead->misc.numTxQueues = 1;
> - tqc = &adapter->tqd_start->conf;
> - tqc->txRingBasePA = cpu_to_le64(adapter->tx_queue.tx_ring.basePA);
> - tqc->dataRingBasePA = cpu_to_le64(adapter->tx_queue.data_ring.basePA);
> - tqc->compRingBasePA = cpu_to_le64(adapter->tx_queue.comp_ring.basePA);
> - tqc->ddPA = cpu_to_le64(virt_to_phys(
> - adapter->tx_queue.buf_info));
> - tqc->txRingSize = cpu_to_le32(adapter->tx_queue.tx_ring.size);
> - tqc->dataRingSize = cpu_to_le32(adapter->tx_queue.data_ring.size);
> - tqc->compRingSize = cpu_to_le32(adapter->tx_queue.comp_ring.size);
> - tqc->ddLen = cpu_to_le32(sizeof(struct vmxnet3_tx_buf_info) *
> - tqc->txRingSize);
> - tqc->intrIdx = adapter->tx_queue.comp_ring.intr_idx;
> + devRead->misc.numTxQueues = adapter->num_tx_queues;
> + for (i = 0; i < adapter->num_tx_queues; i++) {
> + struct vmxnet3_tx_queue *tq = &adapter->tx_queue[i];
> + BUG_ON(adapter->tx_queue[i].tx_ring.base == NULL);
> + tqc = &adapter->tqd_start[i].conf;
> + tqc->txRingBasePA = cpu_to_le64(tq->tx_ring.basePA);
> + tqc->dataRingBasePA = cpu_to_le64(tq->data_ring.basePA);
> + tqc->compRingBasePA = cpu_to_le64(tq->comp_ring.basePA);
> + tqc->ddPA = cpu_to_le64(virt_to_phys(tq->buf_info));
> + tqc->txRingSize = cpu_to_le32(tq->tx_ring.size);
> + tqc->dataRingSize = cpu_to_le32(tq->data_ring.size);
> + tqc->compRingSize = cpu_to_le32(tq->comp_ring.size);
> + tqc->ddLen = cpu_to_le32(
> + sizeof(struct vmxnet3_tx_buf_info) *
> + tqc->txRingSize);
> + tqc->intrIdx = tq->comp_ring.intr_idx;
> + }
>
> /* rx queue settings */
> - devRead->misc.numRxQueues = 1;
> - rqc = &adapter->rqd_start->conf;
> - rqc->rxRingBasePA[0] = cpu_to_le64(adapter->rx_queue.rx_ring[0].basePA);
> - rqc->rxRingBasePA[1] = cpu_to_le64(adapter->rx_queue.rx_ring[1].basePA);
> - rqc->compRingBasePA = cpu_to_le64(adapter->rx_queue.comp_ring.basePA);
> - rqc->ddPA = cpu_to_le64(virt_to_phys(
> - adapter->rx_queue.buf_info));
> - rqc->rxRingSize[0] = cpu_to_le32(adapter->rx_queue.rx_ring[0].size);
> - rqc->rxRingSize[1] = cpu_to_le32(adapter->rx_queue.rx_ring[1].size);
> - rqc->compRingSize = cpu_to_le32(adapter->rx_queue.comp_ring.size);
> - rqc->ddLen = cpu_to_le32(sizeof(struct vmxnet3_rx_buf_info) *
> - (rqc->rxRingSize[0] + rqc->rxRingSize[1]));
> - rqc->intrIdx = adapter->rx_queue.comp_ring.intr_idx;
> + devRead->misc.numRxQueues = adapter->num_rx_queues;
> + for (i = 0; i < adapter->num_rx_queues; i++) {
> + struct vmxnet3_rx_queue *rq = &adapter->rx_queue[i];
> + rqc = &adapter->rqd_start[i].conf;
> + rqc->rxRingBasePA[0] = cpu_to_le64(rq->rx_ring[0].basePA);
> + rqc->rxRingBasePA[1] = cpu_to_le64(rq->rx_ring[1].basePA);
> + rqc->compRingBasePA = cpu_to_le64(rq->comp_ring.basePA);
> + rqc->ddPA = cpu_to_le64(virt_to_phys(
> + rq->buf_info));
> + rqc->rxRingSize[0] = cpu_to_le32(rq->rx_ring[0].size);
> + rqc->rxRingSize[1] = cpu_to_le32(rq->rx_ring[1].size);
> + rqc->compRingSize = cpu_to_le32(rq->comp_ring.size);
> + rqc->ddLen = cpu_to_le32(
> + sizeof(struct vmxnet3_rx_buf_info) *
> + (rqc->rxRingSize[0] +
> + rqc->rxRingSize[1]));
> + rqc->intrIdx = rq->comp_ring.intr_idx;
> + }
> +
> +#ifdef VMXNET3_RSS
> + memset(adapter->rss_conf, 0, sizeof(*adapter->rss_conf));
> +
> + if (adapter->rss) {
> + struct UPT1_RSSConf *rssConf = adapter->rss_conf;
> + devRead->misc.uptFeatures |= UPT1_F_RSS;
> + devRead->misc.numRxQueues = adapter->num_rx_queues;
> + rssConf->hashType = UPT1_RSS_HASH_TYPE_TCP_IPV4 |
> + UPT1_RSS_HASH_TYPE_IPV4 |
> + UPT1_RSS_HASH_TYPE_TCP_IPV6 |
> + UPT1_RSS_HASH_TYPE_IPV6;
> + rssConf->hashFunc = UPT1_RSS_HASH_FUNC_TOEPLITZ;
> + rssConf->hashKeySize = UPT1_RSS_MAX_KEY_SIZE;
> + rssConf->indTableSize = VMXNET3_RSS_IND_TABLE_SIZE;
> + get_random_bytes(&rssConf->hashKey[0], rssConf->hashKeySize);
> + for (i = 0; i < rssConf->indTableSize; i++)
> + rssConf->indTable[i] = i % adapter->num_rx_queues;
> +
> + devRead->rssConfDesc.confVer = 1;
> + devRead->rssConfDesc.confLen = sizeof(*rssConf);
> + devRead->rssConfDesc.confPA = virt_to_phys(rssConf);
> + }
> +
> +#endif /* VMXNET3_RSS */
>
> /* intr settings */
> devRead->intrConf.autoMask = adapter->intr.mask_mode ==
> @@ -1831,18 +2180,18 @@ vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter)
> int
> vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
> {
> - int err;
> + int err, i;
> u32 ret;
>
> - dev_dbg(&adapter->netdev->dev,
> - "%s: skb_buf_size %d, rx_buf_per_pkt %d, ring sizes"
> - " %u %u %u\n", adapter->netdev->name, adapter->skb_buf_size,
> - adapter->rx_buf_per_pkt, adapter->tx_queue.tx_ring.size,
> - adapter->rx_queue.rx_ring[0].size,
> - adapter->rx_queue.rx_ring[1].size);
> -
> - vmxnet3_tq_init(&adapter->tx_queue, adapter);
> - err = vmxnet3_rq_init(&adapter->rx_queue, adapter);
> + dev_dbg(&adapter->netdev->dev, "%s: skb_buf_size %d, rx_buf_per_pkt %d,"
> + " ring sizes %u %u %u\n", adapter->netdev->name,
> + adapter->skb_buf_size, adapter->rx_buf_per_pkt,
> + adapter->tx_queue[0].tx_ring.size,
> + adapter->rx_queue[0].rx_ring[0].size,
> + adapter->rx_queue[0].rx_ring[1].size);
> +
> + vmxnet3_tq_init_all(adapter);
> + err = vmxnet3_rq_init_all(adapter);
> if (err) {
> printk(KERN_ERR "Failed to init rx queue for %s: error %d\n",
> adapter->netdev->name, err);
> @@ -1872,10 +2221,15 @@ vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
> err = -EINVAL;
> goto activate_err;
> }
> - VMXNET3_WRITE_BAR0_REG(adapter, VMXNET3_REG_RXPROD,
> - adapter->rx_queue.rx_ring[0].next2fill);
> - VMXNET3_WRITE_BAR0_REG(adapter, VMXNET3_REG_RXPROD2,
> - adapter->rx_queue.rx_ring[1].next2fill);
> +
> + for (i = 0; i < adapter->num_rx_queues; i++) {
> + VMXNET3_WRITE_BAR0_REG(adapter, (VMXNET3_REG_RXPROD +
> + (i * VMXNET3_REG_ALIGN)),
> + adapter->rx_queue[i].rx_ring[0].next2fill);
> + VMXNET3_WRITE_BAR0_REG(adapter, (VMXNET3_REG_RXPROD2 +
> + (i * VMXNET3_REG_ALIGN)),
> + adapter->rx_queue[i].rx_ring[1].next2fill);
> + }
>
> /* Apply the rx filter settins last. */
> vmxnet3_set_mc(adapter->netdev);
> @@ -1885,8 +2239,8 @@ vmxnet3_activate_dev(struct vmxnet3_adapter *adapter)
> * tx queue if the link is up.
> */
> vmxnet3_check_link(adapter, true);
> -
> - napi_enable(&adapter->napi);
> + for (i = 0; i < adapter->num_rx_queues; i++)
> + napi_enable(&adapter->rx_queue[i].napi);
> vmxnet3_enable_all_intrs(adapter);
> clear_bit(VMXNET3_STATE_BIT_QUIESCED, &adapter->state);
> return 0;
> @@ -1898,7 +2252,7 @@ activate_err:
> irq_err:
> rq_err:
> /* free up buffers we allocated */
> - vmxnet3_rq_cleanup(&adapter->rx_queue, adapter);
> + vmxnet3_rq_cleanup_all(adapter);
> return err;
> }
>
> @@ -1913,6 +2267,7 @@ vmxnet3_reset_dev(struct vmxnet3_adapter *adapter)
> int
> vmxnet3_quiesce_dev(struct vmxnet3_adapter *adapter)
> {
> + int i;
> if (test_and_set_bit(VMXNET3_STATE_BIT_QUIESCED, &adapter->state))
> return 0;
>
> @@ -1921,13 +2276,14 @@ vmxnet3_quiesce_dev(struct vmxnet3_adapter *adapter)
> VMXNET3_CMD_QUIESCE_DEV);
> vmxnet3_disable_all_intrs(adapter);
>
> - napi_disable(&adapter->napi);
> + for (i = 0; i < adapter->num_rx_queues; i++)
> + napi_disable(&adapter->rx_queue[i].napi);
> netif_tx_disable(adapter->netdev);
> adapter->link_speed = 0;
> netif_carrier_off(adapter->netdev);
>
> - vmxnet3_tq_cleanup(&adapter->tx_queue, adapter);
> - vmxnet3_rq_cleanup(&adapter->rx_queue, adapter);
> + vmxnet3_tq_cleanup_all(adapter);
> + vmxnet3_rq_cleanup_all(adapter);
> vmxnet3_free_irqs(adapter);
> return 0;
> }
> @@ -2049,7 +2405,9 @@ vmxnet3_free_pci_resources(struct vmxnet3_adapter *adapter)
> static void
> vmxnet3_adjust_rx_ring_size(struct vmxnet3_adapter *adapter)
> {
> - size_t sz;
> + size_t sz, i, ring0_size, ring1_size, comp_size;
> + struct vmxnet3_rx_queue *rq = &adapter->rx_queue[0];
> +
>
> if (adapter->netdev->mtu <= VMXNET3_MAX_SKB_BUF_SIZE -
> VMXNET3_MAX_ETH_HDR_SIZE) {
> @@ -2071,11 +2429,19 @@ vmxnet3_adjust_rx_ring_size(struct vmxnet3_adapter *adapter)
> * rx_buf_per_pkt * VMXNET3_RING_SIZE_ALIGN
> */
> sz = adapter->rx_buf_per_pkt * VMXNET3_RING_SIZE_ALIGN;
> - adapter->rx_queue.rx_ring[0].size = (adapter->rx_queue.rx_ring[0].size +
> - sz - 1) / sz * sz;
> - adapter->rx_queue.rx_ring[0].size = min_t(u32,
> - adapter->rx_queue.rx_ring[0].size,
> - VMXNET3_RX_RING_MAX_SIZE / sz * sz);
> + ring0_size = adapter->rx_queue[0].rx_ring[0].size;
> + ring0_size = (ring0_size + sz - 1) / sz * sz;
> + ring0_size = min_t(u32, rq->rx_ring[0].size, VMXNET3_RX_RING_MAX_SIZE /
> + sz * sz);
> + ring1_size = adapter->rx_queue[0].rx_ring[1].size;
> + comp_size = ring0_size + ring1_size;
> +
> + for (i = 0; i < adapter->num_rx_queues; i++) {
> + rq = &adapter->rx_queue[i];
> + rq->rx_ring[0].size = ring0_size;
> + rq->rx_ring[1].size = ring1_size;
> + rq->comp_ring.size = comp_size;
> + }
> }
>
>
> @@ -2083,29 +2449,53 @@ int
> vmxnet3_create_queues(struct vmxnet3_adapter *adapter, u32 tx_ring_size,
> u32 rx_ring_size, u32 rx_ring2_size)
> {
> - int err;
> -
> - adapter->tx_queue.tx_ring.size = tx_ring_size;
> - adapter->tx_queue.data_ring.size = tx_ring_size;
> - adapter->tx_queue.comp_ring.size = tx_ring_size;
> - adapter->tx_queue.shared = &adapter->tqd_start->ctrl;
> - adapter->tx_queue.stopped = true;
> - err = vmxnet3_tq_create(&adapter->tx_queue, adapter);
> - if (err)
> - return err;
> + int err = 0, i;
> +
> + for (i = 0; i < adapter->num_tx_queues; i++) {
> + struct vmxnet3_tx_queue *tq = &adapter->tx_queue[i];
> + tq->tx_ring.size = tx_ring_size;
> + tq->data_ring.size = tx_ring_size;
> + tq->comp_ring.size = tx_ring_size;
> + tq->shared = &adapter->tqd_start[i].ctrl;
> + tq->stopped = true;
> + tq->adapter = adapter;
> + tq->qid = i;
> + err = vmxnet3_tq_create(tq, adapter);
> + /*
> + * Too late to change num_tx_queues. We cannot do away with
> + * lesser number of queues than what we asked for
> + */
> + if (err)
> + goto queue_err;
> + }
>
> - adapter->rx_queue.rx_ring[0].size = rx_ring_size;
> - adapter->rx_queue.rx_ring[1].size = rx_ring2_size;
> + adapter->rx_queue[0].rx_ring[0].size = rx_ring_size;
> + adapter->rx_queue[0].rx_ring[1].size = rx_ring2_size;
> vmxnet3_adjust_rx_ring_size(adapter);
> - adapter->rx_queue.comp_ring.size = adapter->rx_queue.rx_ring[0].size +
> - adapter->rx_queue.rx_ring[1].size;
> - adapter->rx_queue.qid = 0;
> - adapter->rx_queue.qid2 = 1;
> - adapter->rx_queue.shared = &adapter->rqd_start->ctrl;
> - err = vmxnet3_rq_create(&adapter->rx_queue, adapter);
> - if (err)
> - vmxnet3_tq_destroy(&adapter->tx_queue, adapter);
> -
> + for (i = 0; i < adapter->num_rx_queues; i++) {
> + struct vmxnet3_rx_queue *rq = &adapter->rx_queue[i];
> + /* qid and qid2 for rx queues will be assigned later when num
> + * of rx queues is finalized after allocating intrs */
> + rq->shared = &adapter->rqd_start[i].ctrl;
> + rq->adapter = adapter;
> + err = vmxnet3_rq_create(rq, adapter);
> + if (err) {
> + if (i == 0) {
> + printk(KERN_ERR "Could not allocate any rx"
> + "queues. Aborting.\n");
> + goto queue_err;
> + } else {
> + printk(KERN_INFO "Number of rx queues changed "
> + "to : %d.\n", i);
> + adapter->num_rx_queues = i;
> + err = 0;
> + break;
> + }
> + }
> + }
> + return err;
> +queue_err:
> + vmxnet3_tq_destroy_all(adapter);
> return err;
> }
>
> @@ -2113,11 +2503,12 @@ static int
> vmxnet3_open(struct net_device *netdev)
> {
> struct vmxnet3_adapter *adapter;
> - int err;
> + int err, i;
>
> adapter = netdev_priv(netdev);
>
> - spin_lock_init(&adapter->tx_queue.tx_lock);
> + for (i = 0; i < adapter->num_tx_queues; i++)
> + spin_lock_init(&adapter->tx_queue[i].tx_lock);
>
> err = vmxnet3_create_queues(adapter, VMXNET3_DEF_TX_RING_SIZE,
> VMXNET3_DEF_RX_RING_SIZE,
> @@ -2132,8 +2523,8 @@ vmxnet3_open(struct net_device *netdev)
> return 0;
>
> activate_err:
> - vmxnet3_rq_destroy(&adapter->rx_queue, adapter);
> - vmxnet3_tq_destroy(&adapter->tx_queue, adapter);
> + vmxnet3_rq_destroy_all(adapter);
> + vmxnet3_tq_destroy_all(adapter);
> queue_err:
> return err;
> }
> @@ -2153,8 +2544,8 @@ vmxnet3_close(struct net_device *netdev)
>
> vmxnet3_quiesce_dev(adapter);
>
> - vmxnet3_rq_destroy(&adapter->rx_queue, adapter);
> - vmxnet3_tq_destroy(&adapter->tx_queue, adapter);
> + vmxnet3_rq_destroy_all(adapter);
> + vmxnet3_tq_destroy_all(adapter);
>
> clear_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state);
>
> @@ -2166,6 +2557,8 @@ vmxnet3_close(struct net_device *netdev)
> void
> vmxnet3_force_close(struct vmxnet3_adapter *adapter)
> {
> + int i;
> +
> /*
> * we must clear VMXNET3_STATE_BIT_RESETTING, otherwise
> * vmxnet3_close() will deadlock.
> @@ -2173,7 +2566,8 @@ vmxnet3_force_close(struct vmxnet3_adapter *adapter)
> BUG_ON(test_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state));
>
> /* we need to enable NAPI, otherwise dev_close will deadlock */
> - napi_enable(&adapter->napi);
> + for (i = 0; i < adapter->num_rx_queues; i++)
> + napi_enable(&adapter->rx_queue[i].napi);
> dev_close(adapter->netdev);
> }
>
> @@ -2204,14 +2598,11 @@ vmxnet3_change_mtu(struct net_device *netdev, int new_mtu)
> vmxnet3_reset_dev(adapter);
>
> /* we need to re-create the rx queue based on the new mtu */
> - vmxnet3_rq_destroy(&adapter->rx_queue, adapter);
> + vmxnet3_rq_destroy_all(adapter);
> vmxnet3_adjust_rx_ring_size(adapter);
> - adapter->rx_queue.comp_ring.size =
> - adapter->rx_queue.rx_ring[0].size +
> - adapter->rx_queue.rx_ring[1].size;
> - err = vmxnet3_rq_create(&adapter->rx_queue, adapter);
> + err = vmxnet3_rq_create_all(adapter);
> if (err) {
> - printk(KERN_ERR "%s: failed to re-create rx queue,"
> + printk(KERN_ERR "%s: failed to re-create rx queues,"
> " error %d. Closing it.\n", netdev->name, err);
> goto out;
> }
> @@ -2276,6 +2667,55 @@ vmxnet3_read_mac_addr(struct vmxnet3_adapter *adapter, u8 *mac)
> mac[5] = (tmp >> 8) & 0xff;
> }
>
> +#ifdef CONFIG_PCI_MSI
> +
> +/*
> + * Enable MSIx vectors.
> + * Returns :
> + * 0 on successful enabling of required vectors,
> + * VMXNET3_LINUX_MIN_MSIX_VECT when only minumum number of vectors required
> + * could be enabled.
> + * number of vectors which can be enabled otherwise (this number is smaller
> + * than VMXNET3_LINUX_MIN_MSIX_VECT)
> + */
> +
> +static int
> +vmxnet3_acquire_msix_vectors(struct vmxnet3_adapter *adapter,
> + int vectors)
> +{
> + int err = 0, vector_threshold;
> + vector_threshold = VMXNET3_LINUX_MIN_MSIX_VECT;
> +
> + while (vectors >= vector_threshold) {
> + err = pci_enable_msix(adapter->pdev, adapter->intr.msix_entries,
> + vectors);
> + if (!err) {
> + adapter->intr.num_intrs = vectors;
> + return 0;
> + } else if (err < 0) {
> + printk(KERN_ERR "Failed to enable MSI-X for %s, error"
> + " %d\n", adapter->netdev->name, err);
> + vectors = 0;
> + } else if (err < vector_threshold) {
> + break;
> + } else {
> + /* If fails to enable required number of MSI-x vectors
> + * try enabling 3 of them. One each for rx, tx and event
> + */
> + vectors = vector_threshold;
> + printk(KERN_ERR "Failed to enable %d MSI-X for %s, try"
> + " %d instead\n", vectors, adapter->netdev->name,
> + vector_threshold);
> + }
> + }
> +
> + printk(KERN_INFO "Number of MSI-X interrupts which can be allocatedi"
> + " are lower than min threshold required.\n");
> + return err;
> +}
> +
> +
> +#endif /* CONFIG_PCI_MSI */
>
> static void
> vmxnet3_alloc_intr_resources(struct vmxnet3_adapter *adapter)
> @@ -2295,16 +2735,47 @@ vmxnet3_alloc_intr_resources(struct vmxnet3_adapter *adapter)
>
> #ifdef CONFIG_PCI_MSI
> if (adapter->intr.type == VMXNET3_IT_MSIX) {
> - int err;
> -
> - adapter->intr.msix_entries[0].entry = 0;
> - err = pci_enable_msix(adapter->pdev, adapter->intr.msix_entries,
> - VMXNET3_LINUX_MAX_MSIX_VECT);
> - if (!err) {
> - adapter->intr.num_intrs = 1;
> - adapter->intr.type = VMXNET3_IT_MSIX;
> + int vector, err = 0;
> +
> + adapter->intr.num_intrs = (adapter->share_intr ==
> + VMXNET3_INTR_TXSHARE) ? 1 :
> + adapter->num_tx_queues;
> + adapter->intr.num_intrs += (adapter->share_intr ==
> + VMXNET3_INTR_BUDDYSHARE) ? 0 :
> + adapter->num_rx_queues;
> + adapter->intr.num_intrs += 1; /* for link event */
> +
> + adapter->intr.num_intrs = (adapter->intr.num_intrs >
> + VMXNET3_LINUX_MIN_MSIX_VECT
> + ? adapter->intr.num_intrs :
> + VMXNET3_LINUX_MIN_MSIX_VECT);
> +
> + for (vector = 0; vector < adapter->intr.num_intrs; vector++)
> + adapter->intr.msix_entries[vector].entry = vector;
> +
> + err = vmxnet3_acquire_msix_vectors(adapter,
> + adapter->intr.num_intrs);
> + /* If we cannot allocate one MSIx vector per queue
> + * then limit the number of rx queues to 1
> + */
> + if (err == VMXNET3_LINUX_MIN_MSIX_VECT) {
> + if (adapter->share_intr != VMXNET3_INTR_BUDDYSHARE
> + || adapter->num_rx_queues != 2) {
> + adapter->share_intr = VMXNET3_INTR_TXSHARE;
> + printk(KERN_ERR "Number of rx queues : 1\n");
> + adapter->num_rx_queues = 1;
> + adapter->intr.num_intrs =
> + VMXNET3_LINUX_MIN_MSIX_VECT;
> + }
> return;
> }
> + if (!err)
> + return;
> +
> + /* If we cannot allocate MSIx vectors use only one rx queue */
> + printk(KERN_INFO "Failed to enable MSI-X for %s, error %d."
> + "#rx queues : 1, try MSI\n", adapter->netdev->name, err);
> +
> adapter->intr.type = VMXNET3_IT_MSI;
> }
>
> @@ -2312,12 +2783,15 @@ vmxnet3_alloc_intr_resources(struct vmxnet3_adapter *adapter)
> int err;
> err = pci_enable_msi(adapter->pdev);
> if (!err) {
> + adapter->num_rx_queues = 1;
> adapter->intr.num_intrs = 1;
> return;
> }
> }
> #endif /* CONFIG_PCI_MSI */
>
> + adapter->num_rx_queues = 1;
> + printk(KERN_INFO "Using INTx interrupt, #Rx queues: 1.\n");
> adapter->intr.type = VMXNET3_IT_INTX;
>
> /* INT-X related setting */
> @@ -2345,6 +2819,7 @@ vmxnet3_tx_timeout(struct net_device *netdev)
>
> printk(KERN_ERR "%s: tx hang\n", adapter->netdev->name);
> schedule_work(&adapter->work);
> + netif_wake_queue(adapter->netdev);
> }
>
>
> @@ -2401,8 +2876,32 @@ vmxnet3_probe_device(struct pci_dev *pdev,
> struct net_device *netdev;
> struct vmxnet3_adapter *adapter;
> u8 mac[ETH_ALEN];
> + int size;
> + int num_tx_queues = enable_mq[atomic_read(&devices_found)] == 0 ? 1 : 0;
> + int num_rx_queues = enable_mq[atomic_read(&devices_found)] == 0 ? 1 : 0;
> +
> +#ifdef VMXNET3_RSS
> + if (num_rx_queues == 0)
> + num_rx_queues = min(VMXNET3_DEVICE_MAX_RX_QUEUES,
> + (int)num_online_cpus());
> + else
> + num_rx_queues = min(VMXNET3_DEVICE_MAX_RX_QUEUES,
> + num_rx_queues);
> +#else
> + num_rx_queues = 1;
> +#endif
> +
> + if (num_tx_queues <= 0)
> + num_tx_queues = min(VMXNET3_DEVICE_MAX_TX_QUEUES,
> + (int)num_online_cpus());
> + else
> + num_tx_queues = min(VMXNET3_DEVICE_MAX_TX_QUEUES,
> + num_tx_queues);
> + netdev = alloc_etherdev_mq(sizeof(struct vmxnet3_adapter),
> + num_tx_queues);
> + printk(KERN_INFO "# of Tx queues : %d, # of Rx queues : %d\n",
> + num_tx_queues, num_rx_queues);
>
> - netdev = alloc_etherdev(sizeof(struct vmxnet3_adapter));
> if (!netdev) {
> printk(KERN_ERR "Failed to alloc ethernet device for adapter "
> "%s\n", pci_name(pdev));
> @@ -2424,9 +2923,12 @@ vmxnet3_probe_device(struct pci_dev *pdev,
> goto err_alloc_shared;
> }
>
> - adapter->tqd_start = pci_alloc_consistent(adapter->pdev,
> - sizeof(struct Vmxnet3_TxQueueDesc) +
> - sizeof(struct Vmxnet3_RxQueueDesc),
> + adapter->num_rx_queues = num_rx_queues;
> + adapter->num_tx_queues = num_tx_queues;
> +
> + size = sizeof(struct Vmxnet3_TxQueueDesc) * adapter->num_tx_queues;
> + size += sizeof(struct Vmxnet3_RxQueueDesc) * adapter->num_rx_queues;
> + adapter->tqd_start = pci_alloc_consistent(adapter->pdev, size,
> &adapter->queue_desc_pa);
>
> if (!adapter->tqd_start) {
> @@ -2435,8 +2937,8 @@ vmxnet3_probe_device(struct pci_dev *pdev,
> err = -ENOMEM;
> goto err_alloc_queue_desc;
> }
> - adapter->rqd_start = (struct Vmxnet3_RxQueueDesc *)(adapter->tqd_start
> - + 1);
> + adapter->rqd_start = (struct Vmxnet3_RxQueueDesc *)(adapter->tqd_start +
> + adapter->num_tx_queues);
>
> adapter->pm_conf = kmalloc(sizeof(struct Vmxnet3_PMConf), GFP_KERNEL);
> if (adapter->pm_conf == NULL) {
> @@ -2446,6 +2948,17 @@ vmxnet3_probe_device(struct pci_dev *pdev,
> goto err_alloc_pm;
> }
>
> +#ifdef VMXNET3_RSS
> +
> + adapter->rss_conf = kmalloc(sizeof(struct UPT1_RSSConf), GFP_KERNEL);
> + if (adapter->rss_conf == NULL) {
> + printk(KERN_ERR "Failed to allocate memory for %s\n",
> + pci_name(pdev));
> + err = -ENOMEM;
> + goto err_alloc_rss;
> + }
> +#endif /* VMXNET3_RSS */
> +
> err = vmxnet3_alloc_pci_resources(adapter, &dma64);
> if (err < 0)
> goto err_alloc_pci;
> @@ -2473,8 +2986,28 @@ vmxnet3_probe_device(struct pci_dev *pdev,
> vmxnet3_declare_features(adapter, dma64);
>
> adapter->dev_number = atomic_read(&devices_found);
> +
> + /*
> + * Sharing intr between corresponding tx and rx queues gets priority
> + * over all tx queues sharing an intr. Also, to use buddy interrupts
> + * number of tx queues should be same as number of rx queues.
> + */
> + if (irq_share_mode[adapter->dev_number] == VMXNET3_INTR_BUDDYSHARE &&
> + adapter->num_tx_queues != adapter->num_rx_queues)
> + adapter->share_intr = VMXNET3_INTR_DONTSHARE;
> +
> vmxnet3_alloc_intr_resources(adapter);
>
> +#ifdef VMXNET3_RSS
> + if (adapter->num_rx_queues > 1 &&
> + adapter->intr.type == VMXNET3_IT_MSIX) {
> + adapter->rss = true;
> + printk(KERN_INFO "RSS is enabled.\n");
> + } else {
> + adapter->rss = false;
> + }
> +#endif
> +
> vmxnet3_read_mac_addr(adapter, mac);
> memcpy(netdev->dev_addr, mac, netdev->addr_len);
>
> @@ -2484,7 +3017,18 @@ vmxnet3_probe_device(struct pci_dev *pdev,
>
> INIT_WORK(&adapter->work, vmxnet3_reset_work);
>
> - netif_napi_add(netdev, &adapter->napi, vmxnet3_poll, 64);
> + if (adapter->intr.type == VMXNET3_IT_MSIX) {
> + int i;
> + for (i = 0; i < adapter->num_rx_queues; i++) {
> + netif_napi_add(adapter->netdev,
> + &adapter->rx_queue[i].napi,
> + vmxnet3_poll_rx_only, 64);
> + }
> + } else {
> + netif_napi_add(adapter->netdev, &adapter->rx_queue[0].napi,
> + vmxnet3_poll, 64);
> + }
> +
> SET_NETDEV_DEV(netdev, &pdev->dev);
> err = register_netdev(netdev);
>
> @@ -2504,11 +3048,14 @@ err_register:
> err_ver:
> vmxnet3_free_pci_resources(adapter);
> err_alloc_pci:
> +#ifdef VMXNET3_RSS
> + kfree(adapter->rss_conf);
> +err_alloc_rss:
> +#endif
> kfree(adapter->pm_conf);
> err_alloc_pm:
> - pci_free_consistent(adapter->pdev, sizeof(struct Vmxnet3_TxQueueDesc) +
> - sizeof(struct Vmxnet3_RxQueueDesc),
> - adapter->tqd_start, adapter->queue_desc_pa);
> + pci_free_consistent(adapter->pdev, size, adapter->tqd_start,
> + adapter->queue_desc_pa);
> err_alloc_queue_desc:
> pci_free_consistent(adapter->pdev, sizeof(struct Vmxnet3_DriverShared),
> adapter->shared, adapter->shared_pa);
> @@ -2524,6 +3071,19 @@ vmxnet3_remove_device(struct pci_dev *pdev)
> {
> struct net_device *netdev = pci_get_drvdata(pdev);
> struct vmxnet3_adapter *adapter = netdev_priv(netdev);
> + int size = 0;
> + int num_rx_queues = enable_mq[adapter->dev_number] == 0 ? 1 : 0;
> +
> +#ifdef VMXNET3_RSS
> + if (num_rx_queues <= 0)
> + num_rx_queues = min(VMXNET3_DEVICE_MAX_RX_QUEUES,
> + (int)num_online_cpus());
> + else
> + num_rx_queues = min(VMXNET3_DEVICE_MAX_RX_QUEUES,
> + num_rx_queues);
> +#else
> + num_rx_queues = 1;
> +#endif
>
> flush_scheduled_work();
>
> @@ -2531,10 +3091,15 @@ vmxnet3_remove_device(struct pci_dev *pdev)
>
> vmxnet3_free_intr_resources(adapter);
> vmxnet3_free_pci_resources(adapter);
> +#ifdef VMXNET3_RSS
> + kfree(adapter->rss_conf);
> +#endif
> kfree(adapter->pm_conf);
> - pci_free_consistent(adapter->pdev, sizeof(struct Vmxnet3_TxQueueDesc) +
> - sizeof(struct Vmxnet3_RxQueueDesc),
> - adapter->tqd_start, adapter->queue_desc_pa);
> +
> + size = sizeof(struct Vmxnet3_TxQueueDesc) * adapter->num_tx_queues;
> + size += sizeof(struct Vmxnet3_RxQueueDesc) * num_rx_queues;
> + pci_free_consistent(adapter->pdev, size, adapter->tqd_start,
> + adapter->queue_desc_pa);
> pci_free_consistent(adapter->pdev, sizeof(struct Vmxnet3_DriverShared),
> adapter->shared, adapter->shared_pa);
> free_netdev(netdev);
> @@ -2565,7 +3130,7 @@ vmxnet3_suspend(struct device *device)
> vmxnet3_free_intr_resources(adapter);
>
> netif_device_detach(netdev);
> - netif_stop_queue(netdev);
> + netif_tx_stop_all_queues(netdev);
>
> /* Create wake-up filters. */
> pmConf = adapter->pm_conf;
> @@ -2710,6 +3275,7 @@ vmxnet3_init_module(void)
> {
> printk(KERN_INFO "%s - version %s\n", VMXNET3_DRIVER_DESC,
> VMXNET3_DRIVER_VERSION_REPORT);
> + atomic_set(&devices_found, 0);
> return pci_register_driver(&vmxnet3_driver);
> }
>
> @@ -2728,3 +3294,5 @@ MODULE_AUTHOR("VMware, Inc.");
> MODULE_DESCRIPTION(VMXNET3_DRIVER_DESC);
> MODULE_LICENSE("GPL v2");
> MODULE_VERSION(VMXNET3_DRIVER_VERSION_STRING);
> +
> +
> diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c
> index 7e4b5a8..73c2bf9 100644
> --- a/drivers/net/vmxnet3/vmxnet3_ethtool.c
> +++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c
> @@ -153,44 +153,42 @@ vmxnet3_get_stats(struct net_device *netdev)
> struct UPT1_TxStats *devTxStats;
> struct UPT1_RxStats *devRxStats;
> struct net_device_stats *net_stats = &netdev->stats;
> + int i;
>
> adapter = netdev_priv(netdev);
>
> /* Collect the dev stats into the shared area */
> VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS);
>
> - /* Assuming that we have a single queue device */
> - devTxStats = &adapter->tqd_start->stats;
> - devRxStats = &adapter->rqd_start->stats;
> -
> - /* Get access to the driver stats per queue */
> - drvTxStats = &adapter->tx_queue.stats;
> - drvRxStats = &adapter->rx_queue.stats;
> -
> memset(net_stats, 0, sizeof(*net_stats));
> + for (i = 0; i < adapter->num_tx_queues; i++) {
> + devTxStats = &adapter->tqd_start[i].stats;
> + drvTxStats = &adapter->tx_queue[i].stats;
> + net_stats->tx_packets += devTxStats->ucastPktsTxOK +
> + devTxStats->mcastPktsTxOK +
> + devTxStats->bcastPktsTxOK;
> + net_stats->tx_bytes += devTxStats->ucastBytesTxOK +
> + devTxStats->mcastBytesTxOK +
> + devTxStats->bcastBytesTxOK;
> + net_stats->tx_errors += devTxStats->pktsTxError;
> + net_stats->tx_dropped += drvTxStats->drop_total;
> + }
>
> - net_stats->rx_packets = devRxStats->ucastPktsRxOK +
> - devRxStats->mcastPktsRxOK +
> - devRxStats->bcastPktsRxOK;
> -
> - net_stats->tx_packets = devTxStats->ucastPktsTxOK +
> - devTxStats->mcastPktsTxOK +
> - devTxStats->bcastPktsTxOK;
> -
> - net_stats->rx_bytes = devRxStats->ucastBytesRxOK +
> - devRxStats->mcastBytesRxOK +
> - devRxStats->bcastBytesRxOK;
> -
> - net_stats->tx_bytes = devTxStats->ucastBytesTxOK +
> - devTxStats->mcastBytesTxOK +
> - devTxStats->bcastBytesTxOK;
> + for (i = 0; i < adapter->num_rx_queues; i++) {
> + devRxStats = &adapter->rqd_start[i].stats;
> + drvRxStats = &adapter->rx_queue[i].stats;
> + net_stats->rx_packets += devRxStats->ucastPktsRxOK +
> + devRxStats->mcastPktsRxOK +
> + devRxStats->bcastPktsRxOK;
>
> - net_stats->rx_errors = devRxStats->pktsRxError;
> - net_stats->tx_errors = devTxStats->pktsTxError;
> - net_stats->rx_dropped = drvRxStats->drop_total;
> - net_stats->tx_dropped = drvTxStats->drop_total;
> - net_stats->multicast = devRxStats->mcastPktsRxOK;
> + net_stats->rx_bytes += devRxStats->ucastBytesRxOK +
> + devRxStats->mcastBytesRxOK +
> + devRxStats->bcastBytesRxOK;
>
> + net_stats->rx_errors += devRxStats->pktsRxError;
> + net_stats->rx_dropped += drvRxStats->drop_total;
> + net_stats->multicast += devRxStats->mcastPktsRxOK;
> + }
> return net_stats;
> }
>
> @@ -309,24 +307,26 @@ vmxnet3_get_ethtool_stats(struct net_device *netdev,
> struct vmxnet3_adapter *adapter = netdev_priv(netdev);
> u8 *base;
> int i;
> + int j = 0;
>
> VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS);
>
> /* this does assume each counter is 64-bit wide */
> +/* TODO change this for multiple queues */
>
> - base = (u8 *)&adapter->tqd_start->stats;
> + base = (u8 *)&adapter->tqd_start[j].stats;
> for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_dev_stats); i++)
> *buf++ = *(u64 *)(base + vmxnet3_tq_dev_stats[i].offset);
>
> - base = (u8 *)&adapter->tx_queue.stats;
> + base = (u8 *)&adapter->tx_queue[j].stats;
> for (i = 0; i < ARRAY_SIZE(vmxnet3_tq_driver_stats); i++)
> *buf++ = *(u64 *)(base + vmxnet3_tq_driver_stats[i].offset);
>
> - base = (u8 *)&adapter->rqd_start->stats;
> + base = (u8 *)&adapter->rqd_start[j].stats;
> for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++)
> *buf++ = *(u64 *)(base + vmxnet3_rq_dev_stats[i].offset);
>
> - base = (u8 *)&adapter->rx_queue.stats;
> + base = (u8 *)&adapter->rx_queue[j].stats;
> for (i = 0; i < ARRAY_SIZE(vmxnet3_rq_driver_stats); i++)
> *buf++ = *(u64 *)(base + vmxnet3_rq_driver_stats[i].offset);
>
> @@ -341,6 +341,7 @@ vmxnet3_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p)
> {
> struct vmxnet3_adapter *adapter = netdev_priv(netdev);
> u32 *buf = p;
> + int i = 0;
>
> memset(p, 0, vmxnet3_get_regs_len(netdev));
>
> @@ -349,28 +350,29 @@ vmxnet3_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p)
> /* Update vmxnet3_get_regs_len if we want to dump more registers */
>
> /* make each ring use multiple of 16 bytes */
> - buf[0] = adapter->tx_queue.tx_ring.next2fill;
> - buf[1] = adapter->tx_queue.tx_ring.next2comp;
> - buf[2] = adapter->tx_queue.tx_ring.gen;
> +/* TODO change this for multiple queues */
> + buf[0] = adapter->tx_queue[i].tx_ring.next2fill;
> + buf[1] = adapter->tx_queue[i].tx_ring.next2comp;
> + buf[2] = adapter->tx_queue[i].tx_ring.gen;
> buf[3] = 0;
>
> - buf[4] = adapter->tx_queue.comp_ring.next2proc;
> - buf[5] = adapter->tx_queue.comp_ring.gen;
> - buf[6] = adapter->tx_queue.stopped;
> + buf[4] = adapter->tx_queue[i].comp_ring.next2proc;
> + buf[5] = adapter->tx_queue[i].comp_ring.gen;
> + buf[6] = adapter->tx_queue[i].stopped;
> buf[7] = 0;
>
> - buf[8] = adapter->rx_queue.rx_ring[0].next2fill;
> - buf[9] = adapter->rx_queue.rx_ring[0].next2comp;
> - buf[10] = adapter->rx_queue.rx_ring[0].gen;
> + buf[8] = adapter->rx_queue[i].rx_ring[0].next2fill;
> + buf[9] = adapter->rx_queue[i].rx_ring[0].next2comp;
> + buf[10] = adapter->rx_queue[i].rx_ring[0].gen;
> buf[11] = 0;
>
> - buf[12] = adapter->rx_queue.rx_ring[1].next2fill;
> - buf[13] = adapter->rx_queue.rx_ring[1].next2comp;
> - buf[14] = adapter->rx_queue.rx_ring[1].gen;
> + buf[12] = adapter->rx_queue[i].rx_ring[1].next2fill;
> + buf[13] = adapter->rx_queue[i].rx_ring[1].next2comp;
> + buf[14] = adapter->rx_queue[i].rx_ring[1].gen;
> buf[15] = 0;
>
> - buf[16] = adapter->rx_queue.comp_ring.next2proc;
> - buf[17] = adapter->rx_queue.comp_ring.gen;
> + buf[16] = adapter->rx_queue[i].comp_ring.next2proc;
> + buf[17] = adapter->rx_queue[i].comp_ring.gen;
> buf[18] = 0;
> buf[19] = 0;
> }
> @@ -437,8 +439,10 @@ vmxnet3_get_ringparam(struct net_device *netdev,
> param->rx_mini_max_pending = 0;
> param->rx_jumbo_max_pending = 0;
>
> - param->rx_pending = adapter->rx_queue.rx_ring[0].size;
> - param->tx_pending = adapter->tx_queue.tx_ring.size;
> + param->rx_pending = adapter->rx_queue[0].rx_ring[0].size *
> + adapter->num_rx_queues;
> + param->tx_pending = adapter->tx_queue[0].tx_ring.size *
> + adapter->num_tx_queues;
> param->rx_mini_pending = 0;
> param->rx_jumbo_pending = 0;
> }
> @@ -482,8 +486,8 @@ vmxnet3_set_ringparam(struct net_device *netdev,
> sz) != 0)
> return -EINVAL;
>
> - if (new_tx_ring_size == adapter->tx_queue.tx_ring.size &&
> - new_rx_ring_size == adapter->rx_queue.rx_ring[0].size) {
> + if (new_tx_ring_size == adapter->tx_queue[0].tx_ring.size &&
> + new_rx_ring_size == adapter->rx_queue[0].rx_ring[0].size) {
> return 0;
> }
>
> @@ -500,11 +504,12 @@ vmxnet3_set_ringparam(struct net_device *netdev,
>
> /* recreate the rx queue and the tx queue based on the
> * new sizes */
> - vmxnet3_tq_destroy(&adapter->tx_queue, adapter);
> - vmxnet3_rq_destroy(&adapter->rx_queue, adapter);
> + vmxnet3_tq_destroy_all(adapter);
> + vmxnet3_rq_destroy_all(adapter);
>
> err = vmxnet3_create_queues(adapter, new_tx_ring_size,
> new_rx_ring_size, VMXNET3_DEF_RX_RING_SIZE);
> +
> if (err) {
> /* failed, most likely because of OOM, try default
> * size */
> @@ -537,6 +542,59 @@ out:
> }
>
>
> +static int
> +vmxnet3_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *info,
> + void *rules)
> +{
> + struct vmxnet3_adapter *adapter = netdev_priv(netdev);
> + switch (info->cmd) {
> + case ETHTOOL_GRXRINGS:
> + info->data = adapter->num_rx_queues;
> + return 0;
> + }
> + return -EOPNOTSUPP;
> +}
> +
> +
> +static int
> +vmxnet3_get_rss_indir(struct net_device *netdev,
> + struct ethtool_rxfh_indir *p)
> +{
> + struct vmxnet3_adapter *adapter = netdev_priv(netdev);
> + struct UPT1_RSSConf *rssConf = adapter->rss_conf;
> + unsigned int n = min_t(unsigned int, p->size, rssConf->indTableSize);
> +
> + p->size = rssConf->indTableSize;
> + while (n--)
> + p->ring_index[n] = rssConf->indTable[n];
> + return 0;
> +
> +}
> +
> +static int
> +vmxnet3_set_rss_indir(struct net_device *netdev,
> + const struct ethtool_rxfh_indir *p)
> +{
> + unsigned int i;
> + struct vmxnet3_adapter *adapter = netdev_priv(netdev);
> + struct UPT1_RSSConf *rssConf = adapter->rss_conf;
> +
> + if (p->size != rssConf->indTableSize)
> + return -EINVAL;
> + for (i = 0; i < rssConf->indTableSize; i++) {
> + if (p->ring_index[i] >= 0 && p->ring_index[i] <
> + adapter->num_rx_queues)
> + rssConf->indTable[i] = p->ring_index[i];
> + else
> + rssConf->indTable[i] = i % adapter->num_rx_queues;
> + }
> + VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
> + VMXNET3_CMD_UPDATE_RSSIDT);
> +
> + return 0;
> +
> +}
> +
> static struct ethtool_ops vmxnet3_ethtool_ops = {
> .get_settings = vmxnet3_get_settings,
> .get_drvinfo = vmxnet3_get_drvinfo,
> @@ -560,6 +618,9 @@ static struct ethtool_ops vmxnet3_ethtool_ops = {
> .get_ethtool_stats = vmxnet3_get_ethtool_stats,
> .get_ringparam = vmxnet3_get_ringparam,
> .set_ringparam = vmxnet3_set_ringparam,
> + .get_rxnfc = vmxnet3_get_rxnfc,
> + .get_rxfh_indir = vmxnet3_get_rss_indir,
> + .set_rxfh_indir = vmxnet3_set_rss_indir,
> };
>
> void vmxnet3_set_ethtool_ops(struct net_device *netdev)
> diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h
> index c88ea5c..2332b1f 100644
> --- a/drivers/net/vmxnet3/vmxnet3_int.h
> +++ b/drivers/net/vmxnet3/vmxnet3_int.h
> @@ -68,11 +68,15 @@
> /*
> * Version numbers
> */
> -#define VMXNET3_DRIVER_VERSION_STRING "1.0.14.0-k"
> +#define VMXNET3_DRIVER_VERSION_STRING "1.0.16.0-k"
>
> /* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */
> -#define VMXNET3_DRIVER_VERSION_NUM 0x01000E00
> +#define VMXNET3_DRIVER_VERSION_NUM 0x01001000
>
> +#if defined(CONFIG_PCI_MSI)
> + /* RSS only makes sense if MSI-X is supported. */
> + #define VMXNET3_RSS
> +#endif
>
> /*
> * Capabilities
> @@ -218,16 +222,19 @@ struct vmxnet3_tx_ctx {
> };
>
> struct vmxnet3_tx_queue {
> + char name[IFNAMSIZ+8]; /* To identify interrupt */
> + struct vmxnet3_adapter *adapter;
> spinlock_t tx_lock;
> struct vmxnet3_cmd_ring tx_ring;
> - struct vmxnet3_tx_buf_info *buf_info;
> + struct vmxnet3_tx_buf_info *buf_info;
> struct vmxnet3_tx_data_ring data_ring;
> struct vmxnet3_comp_ring comp_ring;
> - struct Vmxnet3_TxQueueCtrl *shared;
> + struct Vmxnet3_TxQueueCtrl *shared;
> struct vmxnet3_tq_driver_stats stats;
> bool stopped;
> int num_stop; /* # of times the queue is
> * stopped */
> + int qid;
> } __attribute__((__aligned__(SMP_CACHE_BYTES)));
>
> enum vmxnet3_rx_buf_type {
> @@ -259,6 +266,9 @@ struct vmxnet3_rq_driver_stats {
> };
>
> struct vmxnet3_rx_queue {
> + char name[IFNAMSIZ + 8]; /* To identify interrupt */
> + struct vmxnet3_adapter *adapter;
> + struct napi_struct napi;
> struct vmxnet3_cmd_ring rx_ring[2];
> struct vmxnet3_comp_ring comp_ring;
> struct vmxnet3_rx_ctx rx_ctx;
> @@ -271,7 +281,16 @@ struct vmxnet3_rx_queue {
> struct vmxnet3_rq_driver_stats stats;
> } __attribute__((__aligned__(SMP_CACHE_BYTES)));
>
> -#define VMXNET3_LINUX_MAX_MSIX_VECT 1
> +#define VMXNET3_DEVICE_MAX_TX_QUEUES 8
> +#define VMXNET3_DEVICE_MAX_RX_QUEUES 8 /* Keep this value as a power of 2 */
> +
> +/* Should be less than UPT1_RSS_MAX_IND_TABLE_SIZE */
> +#define VMXNET3_RSS_IND_TABLE_SIZE (VMXNET3_DEVICE_MAX_RX_QUEUES * 4)
> +
> +#define VMXNET3_LINUX_MAX_MSIX_VECT (VMXNET3_DEVICE_MAX_TX_QUEUES + \
> + VMXNET3_DEVICE_MAX_RX_QUEUES + 1)
> +#define VMXNET3_LINUX_MIN_MSIX_VECT 3 /* 1 for each : tx, rx and event */
> +
>
> struct vmxnet3_intr {
> enum vmxnet3_intr_mask_mode mask_mode;
> @@ -279,28 +298,32 @@ struct vmxnet3_intr {
> u8 num_intrs; /* # of intr vectors */
> u8 event_intr_idx; /* idx of the intr vector for event */
> u8 mod_levels[VMXNET3_LINUX_MAX_MSIX_VECT]; /* moderation level */
> + char event_msi_vector_name[IFNAMSIZ+11];
> #ifdef CONFIG_PCI_MSI
> struct msix_entry msix_entries[VMXNET3_LINUX_MAX_MSIX_VECT];
> #endif
> };
>
> +/* Interrupt sharing schemes, share_intr */
> +#define VMXNET3_INTR_DONTSHARE 0 /* each queue has its own irq */
> +#define VMXNET3_INTR_TXSHARE 1 /* All tx queues share one irq */
> +#define VMXNET3_INTR_BUDDYSHARE 2 /* Corresponding tx,rx queues share irq */
> +
> #define VMXNET3_STATE_BIT_RESETTING 0
> #define VMXNET3_STATE_BIT_QUIESCED 1
> -struct vmxnet3_adapter {
> - struct vmxnet3_tx_queue tx_queue;
> - struct vmxnet3_rx_queue rx_queue;
> - struct napi_struct napi;
> - struct vlan_group *vlan_grp;
> -
> - struct vmxnet3_intr intr;
> -
> - struct Vmxnet3_DriverShared *shared;
> - struct Vmxnet3_PMConf *pm_conf;
> - struct Vmxnet3_TxQueueDesc *tqd_start; /* first tx queue desc */
> - struct Vmxnet3_RxQueueDesc *rqd_start; /* first rx queue desc */
> - struct net_device *netdev;
> - struct pci_dev *pdev;
>
> +struct vmxnet3_adapter {
> + struct vmxnet3_tx_queue tx_queue[VMXNET3_DEVICE_MAX_TX_QUEUES];
> + struct vmxnet3_rx_queue rx_queue[VMXNET3_DEVICE_MAX_RX_QUEUES];
> + struct vlan_group *vlan_grp;
> + struct vmxnet3_intr intr;
> + struct Vmxnet3_DriverShared *shared;
> + struct Vmxnet3_PMConf *pm_conf;
> + struct Vmxnet3_TxQueueDesc *tqd_start; /* all tx queue desc */
> + struct Vmxnet3_RxQueueDesc *rqd_start; /* all rx queue desc */
> + struct net_device *netdev;
> + struct net_device_stats net_stats;
> + struct pci_dev *pdev;
> u8 *hw_addr0; /* for BAR 0 */
> u8 *hw_addr1; /* for BAR 1 */
>
> @@ -308,6 +331,12 @@ struct vmxnet3_adapter {
> bool rxcsum;
> bool lro;
> bool jumbo_frame;
> +#ifdef VMXNET3_RSS
> + struct UPT1_RSSConf *rss_conf;
> + bool rss;
> +#endif
> + u32 num_rx_queues;
> + u32 num_tx_queues;
>
> /* rx buffer related */
> unsigned skb_buf_size;
> @@ -327,6 +356,7 @@ struct vmxnet3_adapter {
> unsigned long state; /* VMXNET3_STATE_BIT_xxx */
>
> int dev_number;
> + int share_intr;
> };
>
> #define VMXNET3_WRITE_BAR0_REG(adapter, reg, val) \
> @@ -381,12 +411,10 @@ void
> vmxnet3_reset_dev(struct vmxnet3_adapter *adapter);
>
> void
> -vmxnet3_tq_destroy(struct vmxnet3_tx_queue *tq,
> - struct vmxnet3_adapter *adapter);
> +vmxnet3_tq_destroy_all(struct vmxnet3_adapter *adapter);
>
> void
> -vmxnet3_rq_destroy(struct vmxnet3_rx_queue *rq,
> - struct vmxnet3_adapter *adapter);
> +vmxnet3_rq_destroy_all(struct vmxnet3_adapter *adapter);
>
> int
> vmxnet3_create_queues(struct vmxnet3_adapter *adapter,
>
^ permalink raw reply
* Re: [PATCH 0/9] treewide: convert vprintk uses to %pV
From: Luis R. Rodriguez @ 2010-11-10 22:48 UTC (permalink / raw)
To: Joe Perches
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
netdev-u79uwXL29TY76Z2rM5mHXA,
linux-wireless-u79uwXL29TY76Z2rM5mHXA,
cluster-devel-H+wXaHxf7aLQT0dZR+AlfA,
linux-nilfs-u79uwXL29TY76Z2rM5mHXA,
linux-nfs-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <cover.1289348757.git.joe-6d6DIl74uiNBDgjK7y7TUQ@public.gmane.org>
On Tue, Nov 9, 2010 at 4:35 PM, Joe Perches <joe-6d6DIl74uiNBDgjK7y7TUQ@public.gmane.org> wrote:
> Multiple secessive calls to printk can be interleaved.
> Avoid this possible interleaving by using %pV
>
> Joe Perches (9):
> drivers/gpu/drm/drm_stub.c: Use printf extension %pV
> drivers/isdn/mISDN: Use printf extension %pV
> drivers/net/wireless/ath/debug.c: Use printf extension %pV
> drivers/net/wireless/b43/main.c: Use printf extension %pV
> drivers/net/wireless/b43legacy/main.c: Use printf extension %pV
> fs/gfs2/glock.c: Use printf extension %pV
> fs/nilfs2/super.c: Use printf extension %pV
> fs/quota/dquot.c: Use printf extension %pV
> net/sunrpc/svc.c: Use printf extension %pV
>
> drivers/gpu/drm/drm_stub.c | 14 +++++++--
> drivers/isdn/mISDN/layer1.c | 10 +++++--
> drivers/isdn/mISDN/layer2.c | 12 ++++++--
> drivers/isdn/mISDN/tei.c | 23 +++++++++++----
> drivers/net/wireless/ath/debug.c | 9 +++++-
> drivers/net/wireless/b43/main.c | 48 ++++++++++++++++++++++++--------
> drivers/net/wireless/b43legacy/main.c | 47 ++++++++++++++++++++++++--------
> fs/gfs2/glock.c | 9 +++++-
> fs/nilfs2/super.c | 23 +++++++++++-----
> fs/quota/dquot.c | 12 +++++---
> net/sunrpc/svc.c | 12 +++++---
> 11 files changed, 161 insertions(+), 58 deletions(-)
When was this added upstream BTW? I ask for backport considerations.
Luis
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] macvlan: lockless tx path
From: Ben Greear @ 2010-11-10 22:53 UTC (permalink / raw)
To: Eric Dumazet; +Cc: netdev
In-Reply-To: <1289427705.17691.52.camel@edumazet-laptop>
On 11/10/2010 02:21 PM, Eric Dumazet wrote:
> Le mercredi 10 novembre 2010 à 13:35 -0800, Ben Greear a écrit :
NOTE: I trimmed the CC list..this has nothing in particular to
do with mac-vlans now.
>> So an application that must deal with wraps must poll at the minimal
>> time interval for wrapping 32-bit counters at whatever speed, or it
>> must pay attention to the driver to somehow know that this magic driver
>> can *really* do 64-bit stats properly?
>>
>
> Are you aware that you speak of something that is not specified at all
> in linux ?
>
> Frequency of polling is not part of any RFC. This usually is tunable in
> the _application_. Some people sample stats every 5 minutes, some sample
> every second, and hit the "xxx driver updates its stats every two
> seconds, this sucks"
These '2 sec' granularity bugs are a pain and should be (and have been)
fixed.
> I wrote SNMP apps based on /proc/net/dev and all just work, with any
> versions, any driver. Of course, some of them broke 6 years ago because
> they were 32bit legacy application, running on a 64bit kernel. I never
> asked David to change /proc/net/dev to cap counters to 32bit.
I did similar, and then wrote extra code to detect a 64-bit kernel and if
so assume that the counters wrap at 64 bits so I didn't have to poll so
often to make sure I didn't miss a wrap for a 10G NIC. If instead one wraps at 33
bits and the other at 36, there is no way for me to deal with the wrap
properly w/out explicitly knowing about that 33 and 36.
If the old 32-bit counters in /proc/net/dev instead had a driver that
managed to wrap them at 28 bits, I can't see how your application could
have worked properly, so you must have been assuming that the kernel would
always return a full 32-bit counter.
Now, I'm trying to use netlink api since I'm hoping that is more efficient
and controllable than just reading /proc/net/dev over and over. Netlink
explicitly can return a set of 32-bit counters or 64-bit.
All I want is to ensure than they are actually 32 or 64 bit, not 36 bit crammed in a
64-bit counter. In other words, make the driver and/or kernel do it's
job and abstract access to hardware and return a consistent interface.
>> Please note that just because a counter is less than the previous read,
>> that doesn't by itself tell us if it wrapped once or twice. And, if we
>> don't know at which number of bits it wraps, then we don't know how many
>> to add even if we are certain it wrapped only once.
>>
>
> I repeat : Nothing in /proc/net/dev can tell you when a counter will
> wrap (the counter width).
My primary concern is netlink API now, and even for proc/net/dev, there is no
good reason to show 32-bit counters mixed with 64-bit counters on 64-bit systems.
The kernel can deal with this easily enough, and it should.
>> If netlink reports stats64, then those should only wrap at 64 bits,
>> and if it reports stats32, then wrap at 32-bits.
>>
>
> I believe you are mistaken. We provide stats64 for all drivers, even
> 32bit legacy ones. rtnetlink has no way to report counter widths,
> because nobody cared.
Then it's busted. If it claims to return stats64, but instead is returning
something different, it is wrong. Netlink API still defines a stats32, so
the kernel should use that if it can't reliably deal with 64-bit counters.
Thanks,
Ben
--
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc http://www.candelatech.com
^ permalink raw reply
* Re: [PATCH 0/9] treewide: convert vprintk uses to %pV
From: Joe Perches @ 2010-11-10 23:01 UTC (permalink / raw)
To: Luis R. Rodriguez
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
dri-devel-PD4FTy7X32lNgt0PjOBp9y5qC8QIuHrW,
netdev-u79uwXL29TY76Z2rM5mHXA,
linux-wireless-u79uwXL29TY76Z2rM5mHXA,
cluster-devel-H+wXaHxf7aLQT0dZR+AlfA,
linux-nilfs-u79uwXL29TY76Z2rM5mHXA,
linux-nfs-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <AANLkTinhcbdm8YQOrFVdONODo6K6PcxHYtx5vqnap_3T-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
On Wed, 2010-11-10 at 14:48 -0800, Luis R. Rodriguez wrote:
> When was this added upstream BTW? I ask for backport considerations.
commit 7db6f5fb65a82af03229eef104dc9899c5eecf33
Author: Joe Perches <joe-6d6DIl74uiNBDgjK7y7TUQ@public.gmane.org>
Date: Sun Jun 27 01:02:33 2010 +0000
vsprintf: Recursive vsnprintf: Add "%pV", struct va_format
Add the ability to print a format and va_list from a structure pointer
Allows __dev_printk to be implemented as a single printk while
minimizing string space duplication.
%pV should not be used without some mechanism to verify the
format and argument use ala __attribute__(format (printf(...))).
Signed-off-by: Joe Perches <joe-6d6DIl74uiNBDgjK7y7TUQ@public.gmane.org>
Acked-by: Greg Kroah-Hartman <gregkh-l3A5Bk7waGM@public.gmane.org>
Signed-off-by: David S. Miller <davem-fT/PcQaiUtIeIZ0/mPfg9Q@public.gmane.org>
--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] macvlan: lockless tx path
From: Eric Dumazet @ 2010-11-10 23:24 UTC (permalink / raw)
To: Ben Greear; +Cc: netdev
In-Reply-To: <4CDB226A.8080903@candelatech.com>
Le mercredi 10 novembre 2010 à 14:53 -0800, Ben Greear a écrit :
> Then it's busted. If it claims to return stats64, but instead is returning
> something different, it is wrong. Netlink API still defines a stats32, so
> the kernel should use that if it can't reliably deal with 64-bit counters.
>
It claims nothing like that. You obviously assumed wrong things.
It provides a framework, not a mandatory or exclusive one.
Really this endless discussion is going nowhere.
I suggest you send patches if you want, I am very pleased by current
stats handling.
^ permalink raw reply
* Re: [PATCH] macvlan: lockless tx path
From: Eric Dumazet @ 2010-11-10 23:36 UTC (permalink / raw)
To: Ben Greear; +Cc: netdev
In-Reply-To: <4CDB226A.8080903@candelatech.com>
Le mercredi 10 novembre 2010 à 14:53 -0800, Ben Greear a écrit :
> I did similar, and then wrote extra code to detect a 64-bit kernel and if
> so assume that the counters wrap at 64 bits so I didn't have to poll so
> often to make sure I didn't miss a wrap for a 10G NIC. If instead one wraps at 33
> bits and the other at 36, there is no way for me to deal with the wrap
> properly w/out explicitly knowing about that 33 and 36.
>
How do you define 'wrap around' ? Maybe your definition is wrong.
> If the old 32-bit counters in /proc/net/dev instead had a driver that
> managed to wrap them at 28 bits, I can't see how your application could
> have worked properly, so you must have been assuming that the kernel would
> always return a full 32-bit counter.
I suggest you take a look at various SNMP applications that handle this
just fine. RRD for example. You can patch your favorite driver to cap
the stats to 37, 38, ... 31 or 30 bits, it works.
If you sample values faster than half the period, it works.
This has nothing to do with 32 or 64 bits, really.
Read RFC1230 for a good advice
All the statistics are defined using the
syntax Counter as 32 bit wrap around
counters. Thus, if an interface's
hardware chip set maintains these
statistics in 16-bit counters, then the
agent must read the hardware's counters
frequently enough to prevent loss of
significance, in order to maintain
a 32-bit counter in software."
Yes, 16bit counters _are_ fine, even if provided in a 32bit counter, if
you read value fast enough.
^ permalink raw reply
* Re: [PATCH] macvlan: lockless tx path
From: Ben Greear @ 2010-11-10 23:46 UTC (permalink / raw)
To: Eric Dumazet; +Cc: netdev
In-Reply-To: <1289432184.17691.141.camel@edumazet-laptop>
On 11/10/2010 03:36 PM, Eric Dumazet wrote:
> Le mercredi 10 novembre 2010 à 14:53 -0800, Ben Greear a écrit :
>
>> I did similar, and then wrote extra code to detect a 64-bit kernel and if
>> so assume that the counters wrap at 64 bits so I didn't have to poll so
>> often to make sure I didn't miss a wrap for a 10G NIC. If instead one wraps at 33
>> bits and the other at 36, there is no way for me to deal with the wrap
>> properly w/out explicitly knowing about that 33 and 36.
>>
>
> How do you define 'wrap around' ? Maybe your definition is wrong.
Maybe so. My algorithm looks like:
// uint64 accum;
// uint32 old;
// uint32 new;
if (old > new) {
// This assumes counters wrap at 32 bits (ie, 0xFFFFFFFF).
accum += ((uint32)(0xFFFFFFFF) - old) + new;
}
else if (old < new) {
accum += new - old;
}
old = new;
...
Is there some way I can do this w/out the (0xFFFFFFFF - old),
and thus the assumption of 32-bit counters?
Thanks,
Ben
--
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc http://www.candelatech.com
^ permalink raw reply
* Re: [RESEND PATCH] virtio-net: init link state correctly
From: Rusty Russell @ 2010-11-11 0:45 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: Jason Wang, netdev, linux-kernel, davem, markmc, kvm
In-Reply-To: <20101110150823.GA5622@redhat.com>
On Thu, 11 Nov 2010 01:38:23 am Michael S. Tsirkin wrote:
> On Mon, Nov 08, 2010 at 09:41:27AM +1030, Rusty Russell wrote:
> > On Fri, 5 Nov 2010 08:17:18 pm Jason Wang wrote:
> > > For device that supports VIRTIO_NET_F_STATUS, there's no need to
> > > assume the link is up and we need to call nerif_carrier_off() before
> > > querying device status, otherwise we may get wrong operstate after
> > > diver was loaded because the link watch event was not fired as
> > > expected.
> > >
> > > For device that does not support VIRITO_NET_F_STATUS, we could not get
> > > its status through virtnet_update_status() and what we can only do is
> > > always assuming the link is up.
> > >
> > > Acked-by: Michael S. Tsirkin <mst@redhat.com>
> > > Signed-off-by: Jason Wang <jasowang@redhat.com>
> >
> > Acked-by: Rusty Russell <rusty@rustcorp.com.au>
> >
> > Thanks!
> > Rusty.
>
> Rusty, just to verify: who shall be queueing this up?
Sorry, that was sloppy of me; was meant for DaveM to take.
Sending explicitly now...
Rusty.
^ permalink raw reply
* [PATCH] virtio-net: init link state correctly
From: Rusty Russell @ 2010-11-11 0:45 UTC (permalink / raw)
To: netdev; +Cc: Michael S. Tsirkin, Jason Wang
From: Jason Wang <jasowang@redhat.com>
For device that supports VIRTIO_NET_F_STATUS, there's no need to
assume the link is up and we need to call nerif_carrier_off() before
querying device status, otherwise we may get wrong operstate after
diver was loaded because the link watch event was not fired as
expected.
For device that does not support VIRITO_NET_F_STATUS, we could not get
its status through virtnet_update_status() and what we can only do is
always assuming the link is up.
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
drivers/net/virtio_net.c | 12 +++++++++---
1 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index bb6b67f..b6d4028 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -986,9 +986,15 @@ static int virtnet_probe(struct virtio_device *vdev)
goto unregister;
}
- vi->status = VIRTIO_NET_S_LINK_UP;
- virtnet_update_status(vi);
- netif_carrier_on(dev);
+ /* Assume link up if device can't report link status,
+ otherwise get link status from config. */
+ if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) {
+ netif_carrier_off(dev);
+ virtnet_update_status(vi);
+ } else {
+ vi->status = VIRTIO_NET_S_LINK_UP;
+ netif_carrier_on(dev);
+ }
pr_debug("virtnet: registered device %s\n", dev->name);
return 0;
^ permalink raw reply related
* [PATCH 00/10] cxgb4vf: a number of bug fixes and minor cleanup
From: Casey Leedom @ 2010-11-11 2:01 UTC (permalink / raw)
To: netdev; +Cc: David Miller
The following patch set includes a number of bug fixes and some minor cleanup for the cxgb4vf network driver. If there are any problems with formatting, etc. of the patch set please just reject the patch set and kick my butt — I'm still a novice at putting these together!
drivers/net/cxgb4vf/adapter.h | 2 +-
drivers/net/cxgb4vf/cxgb4vf_main.c | 72 +++++++++++++-------
drivers/net/cxgb4vf/sge.c | 131 ++++++++++++++++++++++--------------
drivers/net/cxgb4vf/t4vf_common.h | 29 ++++----
drivers/net/cxgb4vf/t4vf_hw.c | 23 ++++++-
5 files changed, 165 insertions(+), 92 deletions(-)
Casey
^ permalink raw reply
* [PATCH 02/10] cxgb4vf: don't implement trivial (and incorrect) ndo_select_queue()
From: Casey Leedom @ 2010-11-11 2:04 UTC (permalink / raw)
To: netdev; +Cc: davem, Casey Leedom
In-Reply-To: <450C6E98-D0D9-42A6-9F15-4DB98647DB04@chelsio.com>
Don't implement (struct net_device_ops *)->ndo_select_queue() with simple
call to skb_tx_hash(). This leads to non-persistent TX queue selection in
the Linux dev_pick_tx() routine for TCP connections.
Signed-off-by: Casey Leedom <leedom@chelsio.com>
---
drivers/net/cxgb4vf/cxgb4vf_main.c | 14 --------------
1 files changed, 0 insertions(+), 14 deletions(-)
diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c
index f5259a1..224b36c 100644
--- a/drivers/net/cxgb4vf/cxgb4vf_main.c
+++ b/drivers/net/cxgb4vf/cxgb4vf_main.c
@@ -1103,18 +1103,6 @@ static int cxgb4vf_set_mac_addr(struct net_device *dev, void *_addr)
return 0;
}
-/*
- * Return a TX Queue on which to send the specified skb.
- */
-static u16 cxgb4vf_select_queue(struct net_device *dev, struct sk_buff *skb)
-{
- /*
- * XXX For now just use the default hash but we probably want to
- * XXX look at other possibilities ...
- */
- return skb_tx_hash(dev, skb);
-}
-
#ifdef CONFIG_NET_POLL_CONTROLLER
/*
* Poll all of our receive queues. This is called outside of normal interrupt
@@ -2417,7 +2405,6 @@ static const struct net_device_ops cxgb4vf_netdev_ops = {
.ndo_get_stats = cxgb4vf_get_stats,
.ndo_set_rx_mode = cxgb4vf_set_rxmode,
.ndo_set_mac_address = cxgb4vf_set_mac_addr,
- .ndo_select_queue = cxgb4vf_select_queue,
.ndo_validate_addr = eth_validate_addr,
.ndo_do_ioctl = cxgb4vf_do_ioctl,
.ndo_change_mtu = cxgb4vf_change_mtu,
@@ -2623,7 +2610,6 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev,
netdev->do_ioctl = cxgb4vf_do_ioctl;
netdev->change_mtu = cxgb4vf_change_mtu;
netdev->set_mac_address = cxgb4vf_set_mac_addr;
- netdev->select_queue = cxgb4vf_select_queue;
#ifdef CONFIG_NET_POLL_CONTROLLER
netdev->poll_controller = cxgb4vf_poll_controller;
#endif
--
1.7.0.4
^ permalink raw reply related
* [PATCH 01/10] cxgb4vf: minor comment/symbolic name cleanup.
From: Casey Leedom @ 2010-11-11 2:04 UTC (permalink / raw)
To: netdev; +Cc: davem, Casey Leedom
In-Reply-To: <450C6E98-D0D9-42A6-9F15-4DB98647DB04@chelsio.com>
Minor cleanup of comments and symbolic constant names for clarity.
Signed-off-by: Casey Leedom <leedom@chelsio.com>
---
drivers/net/cxgb4vf/adapter.h | 2 +-
drivers/net/cxgb4vf/cxgb4vf_main.c | 9 ++++-----
drivers/net/cxgb4vf/sge.c | 9 ++++++---
drivers/net/cxgb4vf/t4vf_hw.c | 4 ++--
4 files changed, 13 insertions(+), 11 deletions(-)
diff --git a/drivers/net/cxgb4vf/adapter.h b/drivers/net/cxgb4vf/adapter.h
index 8ea0196..4766b41 100644
--- a/drivers/net/cxgb4vf/adapter.h
+++ b/drivers/net/cxgb4vf/adapter.h
@@ -60,7 +60,7 @@ enum {
* MSI-X interrupt index usage.
*/
MSIX_FW = 0, /* MSI-X index for firmware Q */
- MSIX_NIQFLINT = 1, /* MSI-X index base for Ingress Qs */
+ MSIX_IQFLINT = 1, /* MSI-X index base for Ingress Qs */
MSIX_EXTRAS = 1,
MSIX_ENTRIES = MAX_ETH_QSETS + MSIX_EXTRAS,
diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c
index 6de5e2e..f5259a1 100644
--- a/drivers/net/cxgb4vf/cxgb4vf_main.c
+++ b/drivers/net/cxgb4vf/cxgb4vf_main.c
@@ -280,7 +280,7 @@ static void name_msix_vecs(struct adapter *adapter)
const struct port_info *pi = netdev_priv(dev);
int qs, msi;
- for (qs = 0, msi = MSIX_NIQFLINT;
+ for (qs = 0, msi = MSIX_IQFLINT;
qs < pi->nqsets;
qs++, msi++) {
snprintf(adapter->msix_info[msi].desc, namelen,
@@ -309,7 +309,7 @@ static int request_msix_queue_irqs(struct adapter *adapter)
/*
* Ethernet queues.
*/
- msi = MSIX_NIQFLINT;
+ msi = MSIX_IQFLINT;
for_each_ethrxq(s, rxq) {
err = request_irq(adapter->msix_info[msi].vec,
t4vf_sge_intr_msix, 0,
@@ -337,7 +337,7 @@ static void free_msix_queue_irqs(struct adapter *adapter)
int rxq, msi;
free_irq(adapter->msix_info[MSIX_FW].vec, &s->fw_evtq);
- msi = MSIX_NIQFLINT;
+ msi = MSIX_IQFLINT;
for_each_ethrxq(s, rxq)
free_irq(adapter->msix_info[msi++].vec,
&s->ethrxq[rxq].rspq);
@@ -527,7 +527,7 @@ static int setup_sge_queues(struct adapter *adapter)
* brought up at which point lots of things get nailed down
* permanently ...
*/
- msix = MSIX_NIQFLINT;
+ msix = MSIX_IQFLINT;
for_each_port(adapter, pidx) {
struct net_device *dev = adapter->port[pidx];
struct port_info *pi = netdev_priv(dev);
@@ -2465,7 +2465,6 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev,
version_printed = 1;
}
-
/*
* Initialize generic PCI device state.
*/
diff --git a/drivers/net/cxgb4vf/sge.c b/drivers/net/cxgb4vf/sge.c
index f10864d..d791adb 100644
--- a/drivers/net/cxgb4vf/sge.c
+++ b/drivers/net/cxgb4vf/sge.c
@@ -1536,6 +1536,9 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp,
} else
skb_checksum_none_assert(skb);
+ /*
+ * Deliver the packet to the stack.
+ */
if (unlikely(pkt->vlan_ex)) {
struct vlan_group *grp = pi->vlan_grp;
@@ -2115,7 +2118,7 @@ int t4vf_sge_alloc_rxq(struct adapter *adapter, struct sge_rspq *rspq,
/*
* Calculate the size of the hardware free list ring plus
- * status page (which the SGE will place at the end of the
+ * Status Page (which the SGE will place after the end of the
* free list ring) in Egress Queue Units.
*/
flsz = (fl->size / FL_PER_EQ_UNIT +
@@ -2212,8 +2215,8 @@ int t4vf_sge_alloc_eth_txq(struct adapter *adapter, struct sge_eth_txq *txq,
struct port_info *pi = netdev_priv(dev);
/*
- * Calculate the size of the hardware TX Queue (including the
- * status age on the end) in units of TX Descriptors.
+ * Calculate the size of the hardware TX Queue (including the Status
+ * Page on the end of the TX Queue) in units of TX Descriptors.
*/
nentries = txq->q.size + STAT_LEN / sizeof(struct tx_desc);
diff --git a/drivers/net/cxgb4vf/t4vf_hw.c b/drivers/net/cxgb4vf/t4vf_hw.c
index ea1c123..2180181 100644
--- a/drivers/net/cxgb4vf/t4vf_hw.c
+++ b/drivers/net/cxgb4vf/t4vf_hw.c
@@ -1257,7 +1257,7 @@ int t4vf_eth_eq_free(struct adapter *adapter, unsigned int eqid)
*/
int t4vf_handle_fw_rpl(struct adapter *adapter, const __be64 *rpl)
{
- struct fw_cmd_hdr *cmd_hdr = (struct fw_cmd_hdr *)rpl;
+ const struct fw_cmd_hdr *cmd_hdr = (const struct fw_cmd_hdr *)rpl;
u8 opcode = FW_CMD_OP_GET(be32_to_cpu(cmd_hdr->hi));
switch (opcode) {
@@ -1265,7 +1265,7 @@ int t4vf_handle_fw_rpl(struct adapter *adapter, const __be64 *rpl)
/*
* Link/module state change message.
*/
- const struct fw_port_cmd *port_cmd = (void *)rpl;
+ const struct fw_port_cmd *port_cmd = (const void *)rpl;
u32 word;
int action, port_id, link_ok, speed, fc, pidx;
--
1.7.0.4
^ permalink raw reply related
* [PATCH 04/10] cxgb4vf: fix some errors in Gather List to skb conversion
From: Casey Leedom @ 2010-11-11 2:04 UTC (permalink / raw)
To: netdev; +Cc: davem, Casey Leedom
In-Reply-To: <450C6E98-D0D9-42A6-9F15-4DB98647DB04@chelsio.com>
There were some errors in the way that internal Gather Lists were being
translated into skb's. This also makes the VF Driver look more like the PF
Driver to facilitate easier comarison.
Signed-off-by: Casey Leedom <leedom@chelsio.com>
---
drivers/net/cxgb4vf/sge.c | 121 +++++++++++++++++++++++++++-----------------
1 files changed, 74 insertions(+), 47 deletions(-)
diff --git a/drivers/net/cxgb4vf/sge.c b/drivers/net/cxgb4vf/sge.c
index 1767bda..e0b3d1b 100644
--- a/drivers/net/cxgb4vf/sge.c
+++ b/drivers/net/cxgb4vf/sge.c
@@ -154,13 +154,14 @@ enum {
*/
RX_COPY_THRES = 256,
RX_PULL_LEN = 128,
-};
-/*
- * Can't define this in the above enum because PKTSHIFT isn't a constant in
- * the VF Driver ...
- */
-#define RX_PKT_PULL_LEN (RX_PULL_LEN + PKTSHIFT)
+ /*
+ * Main body length for sk_buffs used for RX Ethernet packets with
+ * fragments. Should be >= RX_PULL_LEN but possibly bigger to give
+ * pskb_may_pull() some room.
+ */
+ RX_SKB_LEN = 512,
+};
/*
* Software state per TX descriptor.
@@ -1355,6 +1356,67 @@ out_free:
}
/**
+ * t4vf_pktgl_to_skb - build an sk_buff from a packet gather list
+ * @gl: the gather list
+ * @skb_len: size of sk_buff main body if it carries fragments
+ * @pull_len: amount of data to move to the sk_buff's main body
+ *
+ * Builds an sk_buff from the given packet gather list. Returns the
+ * sk_buff or %NULL if sk_buff allocation failed.
+ */
+struct sk_buff *t4vf_pktgl_to_skb(const struct pkt_gl *gl,
+ unsigned int skb_len, unsigned int pull_len)
+{
+ struct sk_buff *skb;
+ struct skb_shared_info *ssi;
+
+ /*
+ * If the ingress packet is small enough, allocate an skb large enough
+ * for all of the data and copy it inline. Otherwise, allocate an skb
+ * with enough room to pull in the header and reference the rest of
+ * the data via the skb fragment list.
+ *
+ * Below we rely on RX_COPY_THRES being less than the smallest Rx
+ * buff! size, which is expected since buffers are at least
+ * PAGE_SIZEd. In this case packets up to RX_COPY_THRES have only one
+ * fragment.
+ */
+ if (gl->tot_len <= RX_COPY_THRES) {
+ /* small packets have only one fragment */
+ skb = alloc_skb(gl->tot_len, GFP_ATOMIC);
+ if (unlikely(!skb))
+ goto out;
+ __skb_put(skb, gl->tot_len);
+ skb_copy_to_linear_data(skb, gl->va, gl->tot_len);
+ } else {
+ skb = alloc_skb(skb_len, GFP_ATOMIC);
+ if (unlikely(!skb))
+ goto out;
+ __skb_put(skb, pull_len);
+ skb_copy_to_linear_data(skb, gl->va, pull_len);
+
+ ssi = skb_shinfo(skb);
+ ssi->frags[0].page = gl->frags[0].page;
+ ssi->frags[0].page_offset = gl->frags[0].page_offset + pull_len;
+ ssi->frags[0].size = gl->frags[0].size - pull_len;
+ if (gl->nfrags > 1)
+ memcpy(&ssi->frags[1], &gl->frags[1],
+ (gl->nfrags-1) * sizeof(skb_frag_t));
+ ssi->nr_frags = gl->nfrags;
+
+ skb->len = gl->tot_len;
+ skb->data_len = skb->len - pull_len;
+ skb->truesize += skb->data_len;
+
+ /* Get a reference for the last page, we don't own it */
+ get_page(gl->frags[gl->nfrags - 1].page);
+ }
+
+out:
+ return skb;
+}
+
+/**
* t4vf_pktgl_free - free a packet gather list
* @gl: the gather list
*
@@ -1463,10 +1525,8 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp,
{
struct sk_buff *skb;
struct port_info *pi;
- struct skb_shared_info *ssi;
const struct cpl_rx_pkt *pkt = (void *)&rsp[1];
bool csum_ok = pkt->csum_calc && !pkt->err_vec;
- unsigned int len = be16_to_cpu(pkt->len);
struct sge_eth_rxq *rxq = container_of(rspq, struct sge_eth_rxq, rspq);
/*
@@ -1481,42 +1541,14 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp,
}
/*
- * If the ingress packet is small enough, allocate an skb large enough
- * for all of the data and copy it inline. Otherwise, allocate an skb
- * with enough room to pull in the header and reference the rest of
- * the data via the skb fragment list.
+ * Convert the Packet Gather List into an skb.
*/
- if (len <= RX_COPY_THRES) {
- /* small packets have only one fragment */
- skb = alloc_skb(gl->frags[0].size, GFP_ATOMIC);
- if (!skb)
- goto nomem;
- __skb_put(skb, gl->frags[0].size);
- skb_copy_to_linear_data(skb, gl->va, gl->frags[0].size);
- } else {
- skb = alloc_skb(RX_PKT_PULL_LEN, GFP_ATOMIC);
- if (!skb)
- goto nomem;
- __skb_put(skb, RX_PKT_PULL_LEN);
- skb_copy_to_linear_data(skb, gl->va, RX_PKT_PULL_LEN);
-
- ssi = skb_shinfo(skb);
- ssi->frags[0].page = gl->frags[0].page;
- ssi->frags[0].page_offset = (gl->frags[0].page_offset +
- RX_PKT_PULL_LEN);
- ssi->frags[0].size = gl->frags[0].size - RX_PKT_PULL_LEN;
- if (gl->nfrags > 1)
- memcpy(&ssi->frags[1], &gl->frags[1],
- (gl->nfrags-1) * sizeof(skb_frag_t));
- ssi->nr_frags = gl->nfrags;
- skb->len = len + PKTSHIFT;
- skb->data_len = skb->len - RX_PKT_PULL_LEN;
- skb->truesize += skb->data_len;
-
- /* Get a reference for the last page, we don't own it */
- get_page(gl->frags[gl->nfrags - 1].page);
+ skb = t4vf_pktgl_to_skb(gl, RX_SKB_LEN, RX_PULL_LEN);
+ if (unlikely(!skb)) {
+ t4vf_pktgl_free(gl);
+ rxq->stats.rx_drops++;
+ return 0;
}
-
__skb_pull(skb, PKTSHIFT);
skb->protocol = eth_type_trans(skb, rspq->netdev);
skb_record_rx_queue(skb, rspq->idx);
@@ -1552,11 +1584,6 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp,
netif_receive_skb(skb);
return 0;
-
-nomem:
- t4vf_pktgl_free(gl);
- rxq->stats.rx_drops++;
- return 0;
}
/**
--
1.7.0.4
^ permalink raw reply related
* [PATCH 03/10] cxgb4vf: fix bug in Generic Receive Offload
From: Casey Leedom @ 2010-11-11 2:04 UTC (permalink / raw)
To: netdev; +Cc: davem, Casey Leedom
In-Reply-To: <450C6E98-D0D9-42A6-9F15-4DB98647DB04@chelsio.com>
Fix botch in Generic Receive Offload (the Packet Gather List Total length
field wasn't being initialized). Also add ethtool statistics for GRO.
Signed-off-by: Casey Leedom <leedom@chelsio.com>
---
drivers/net/cxgb4vf/cxgb4vf_main.c | 6 ++++++
drivers/net/cxgb4vf/sge.c | 1 +
2 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c
index 224b36c..9e9e4f6 100644
--- a/drivers/net/cxgb4vf/cxgb4vf_main.c
+++ b/drivers/net/cxgb4vf/cxgb4vf_main.c
@@ -1346,6 +1346,8 @@ struct queue_port_stats {
u64 rx_csum;
u64 vlan_ex;
u64 vlan_ins;
+ u64 lro_pkts;
+ u64 lro_merged;
};
/*
@@ -1383,6 +1385,8 @@ static const char stats_strings[][ETH_GSTRING_LEN] = {
"RxCsumGood ",
"VLANextractions ",
"VLANinsertions ",
+ "GROPackets ",
+ "GROMerged ",
};
/*
@@ -1432,6 +1436,8 @@ static void collect_sge_port_stats(const struct adapter *adapter,
stats->rx_csum += rxq->stats.rx_cso;
stats->vlan_ex += rxq->stats.vlan_ex;
stats->vlan_ins += txq->vlan_ins;
+ stats->lro_pkts += rxq->stats.lro_pkts;
+ stats->lro_merged += rxq->stats.lro_merged;
}
}
diff --git a/drivers/net/cxgb4vf/sge.c b/drivers/net/cxgb4vf/sge.c
index d791adb..1767bda 100644
--- a/drivers/net/cxgb4vf/sge.c
+++ b/drivers/net/cxgb4vf/sge.c
@@ -1682,6 +1682,7 @@ int process_responses(struct sge_rspq *rspq, int budget)
}
len = RSPD_LEN(len);
}
+ gl.tot_len = len;
/*
* Gather packet fragments.
--
1.7.0.4
^ permalink raw reply related
* [PATCH 06/10] cxgb4vf: fix up "Section Mismatch" compiler warning.
From: Casey Leedom @ 2010-11-11 2:04 UTC (permalink / raw)
To: netdev; +Cc: davem, Casey Leedom
In-Reply-To: <450C6E98-D0D9-42A6-9F15-4DB98647DB04@chelsio.com>
Fix up "Section Mismatch" compiler warning and mark another routine as
__devinit.
Signed-off-by: Casey Leedom <leedom@chelsio.com>
---
drivers/net/cxgb4vf/cxgb4vf_main.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c
index 75b85ca..b5c0bff 100644
--- a/drivers/net/cxgb4vf/cxgb4vf_main.c
+++ b/drivers/net/cxgb4vf/cxgb4vf_main.c
@@ -2032,7 +2032,7 @@ static int __devinit setup_debugfs(struct adapter *adapter)
* Tear down the /sys/kernel/debug/cxgb4vf sub-nodes created above. We leave
* it to our caller to tear down the directory (debugfs_root).
*/
-static void __devexit cleanup_debugfs(struct adapter *adapter)
+static void cleanup_debugfs(struct adapter *adapter)
{
BUG_ON(adapter->debugfs_root == NULL);
@@ -2050,7 +2050,7 @@ static void __devexit cleanup_debugfs(struct adapter *adapter)
* adapter parameters we're going to be using and initialize basic adapter
* hardware support.
*/
-static int adap_init0(struct adapter *adapter)
+static int __devinit adap_init0(struct adapter *adapter)
{
struct vf_resources *vfres = &adapter->params.vfres;
struct sge_params *sge_params = &adapter->params.sge;
--
1.7.0.4
^ permalink raw reply related
* [PATCH 05/10] cxgb4vf: flesh out PCI Device ID Table ...
From: Casey Leedom @ 2010-11-11 2:04 UTC (permalink / raw)
To: netdev; +Cc: davem, Casey Leedom
In-Reply-To: <450C6E98-D0D9-42A6-9F15-4DB98647DB04@chelsio.com>
Add a bunch of T4 Device IDs for the VF Driver.
Signed-off-by: Casey Leedom <leedom@chelsio.com>
---
drivers/net/cxgb4vf/cxgb4vf_main.c | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c
index 9e9e4f6..75b85ca 100644
--- a/drivers/net/cxgb4vf/cxgb4vf_main.c
+++ b/drivers/net/cxgb4vf/cxgb4vf_main.c
@@ -2834,6 +2834,14 @@ static struct pci_device_id cxgb4vf_pci_tbl[] = {
CH_DEVICE(0x4800, 0), /* T440-dbg */
CH_DEVICE(0x4801, 0), /* T420-cr */
CH_DEVICE(0x4802, 0), /* T422-cr */
+ CH_DEVICE(0x4803, 0), /* T440-cr */
+ CH_DEVICE(0x4804, 0), /* T420-bch */
+ CH_DEVICE(0x4805, 0), /* T440-bch */
+ CH_DEVICE(0x4806, 0), /* T460-ch */
+ CH_DEVICE(0x4807, 0), /* T420-so */
+ CH_DEVICE(0x4808, 0), /* T420-cx */
+ CH_DEVICE(0x4809, 0), /* T420-bt */
+ CH_DEVICE(0x480a, 0), /* T404-bt */
{ 0, }
};
--
1.7.0.4
^ permalink raw reply related
* [PATCH 07/10] cxgb4vf: Fail open if link_start() fails.
From: Casey Leedom @ 2010-11-11 2:04 UTC (permalink / raw)
To: netdev; +Cc: davem, Casey Leedom
In-Reply-To: <450C6E98-D0D9-42A6-9F15-4DB98647DB04@chelsio.com>
Fail open if link_start() fails.
Signed-off-by: Casey Leedom <leedom@chelsio.com>
---
drivers/net/cxgb4vf/cxgb4vf_main.c | 4 +++-
1 files changed, 3 insertions(+), 1 deletions(-)
diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c
index b5c0bff..2d09e83 100644
--- a/drivers/net/cxgb4vf/cxgb4vf_main.c
+++ b/drivers/net/cxgb4vf/cxgb4vf_main.c
@@ -753,7 +753,9 @@ static int cxgb4vf_open(struct net_device *dev)
if (err)
return err;
set_bit(pi->port_id, &adapter->open_device_map);
- link_start(dev);
+ err = link_start(dev);
+ if (err)
+ return err;
netif_tx_start_all_queues(dev);
return 0;
}
--
1.7.0.4
^ permalink raw reply related
* [PATCH 08/10] cxgb4vf: Advertise NETIF_F_TSO_ECN.
From: Casey Leedom @ 2010-11-11 2:04 UTC (permalink / raw)
To: netdev; +Cc: davem, Casey Leedom
In-Reply-To: <450C6E98-D0D9-42A6-9F15-4DB98647DB04@chelsio.com>
Advertise NETIF_F_TSO_ECN.
Signed-off-by: Casey Leedom <leedom@chelsio.com>
---
drivers/net/cxgb4vf/cxgb4vf_main.c | 11 ++++++++---
1 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c
index 2d09e83..15b14ef 100644
--- a/drivers/net/cxgb4vf/cxgb4vf_main.c
+++ b/drivers/net/cxgb4vf/cxgb4vf_main.c
@@ -1536,14 +1536,19 @@ static void cxgb4vf_get_wol(struct net_device *dev,
}
/*
+ * TCP Segmentation Offload flags which we support.
+ */
+#define TSO_FLAGS (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN)
+
+/*
* Set TCP Segmentation Offloading feature capabilities.
*/
static int cxgb4vf_set_tso(struct net_device *dev, u32 tso)
{
if (tso)
- dev->features |= NETIF_F_TSO | NETIF_F_TSO6;
+ dev->features |= TSO_FLAGS;
else
- dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
+ dev->features &= ~TSO_FLAGS;
return 0;
}
@@ -2596,7 +2601,7 @@ static int __devinit cxgb4vf_pci_probe(struct pci_dev *pdev,
netif_carrier_off(netdev);
netdev->irq = pdev->irq;
- netdev->features = (NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6 |
+ netdev->features = (NETIF_F_SG | TSO_FLAGS |
NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
NETIF_F_GRO);
--
1.7.0.4
^ permalink raw reply related
* [PATCH 09/10] cxgb4vf: Mark "UDP [RSS Hash] Enable" as a 1-bit field.
From: Casey Leedom @ 2010-11-11 2:04 UTC (permalink / raw)
To: netdev; +Cc: davem, Casey Leedom
In-Reply-To: <450C6E98-D0D9-42A6-9F15-4DB98647DB04@chelsio.com>
Mark the UDP RSS Hash Enable field as 1-bit in length. Also clean up
formatting from previous changeset which changed the RSS 1-bit fields from
"int" to "unsigned int".
Signed-off-by: Casey Leedom <leedom@chelsio.com>
---
drivers/net/cxgb4vf/t4vf_common.h | 28 ++++++++++++++--------------
1 files changed, 14 insertions(+), 14 deletions(-)
diff --git a/drivers/net/cxgb4vf/t4vf_common.h b/drivers/net/cxgb4vf/t4vf_common.h
index 873cb7d..659616b 100644
--- a/drivers/net/cxgb4vf/t4vf_common.h
+++ b/drivers/net/cxgb4vf/t4vf_common.h
@@ -132,15 +132,15 @@ struct rss_params {
unsigned int mode; /* RSS mode */
union {
struct {
- unsigned int synmapen:1; /* SYN Map Enable */
- unsigned int syn4tupenipv6:1; /* enable hashing 4-tuple IPv6 SYNs */
- unsigned int syn2tupenipv6:1; /* enable hashing 2-tuple IPv6 SYNs */
- unsigned int syn4tupenipv4:1; /* enable hashing 4-tuple IPv4 SYNs */
- unsigned int syn2tupenipv4:1; /* enable hashing 2-tuple IPv4 SYNs */
- unsigned int ofdmapen:1; /* Offload Map Enable */
- unsigned int tnlmapen:1; /* Tunnel Map Enable */
- unsigned int tnlalllookup:1; /* Tunnel All Lookup */
- unsigned int hashtoeplitz:1; /* use Toeplitz hash */
+ uint synmapen:1; /* SYN Map Enable */
+ uint syn4tupenipv6:1; /* enable hashing 4-tuple IPv6 SYNs */
+ uint syn2tupenipv6:1; /* enable hashing 2-tuple IPv6 SYNs */
+ uint syn4tupenipv4:1; /* enable hashing 4-tuple IPv4 SYNs */
+ uint syn2tupenipv4:1; /* enable hashing 2-tuple IPv4 SYNs */
+ uint ofdmapen:1; /* Offload Map Enable */
+ uint tnlmapen:1; /* Tunnel Map Enable */
+ uint tnlalllookup:1; /* Tunnel All Lookup */
+ uint hashtoeplitz:1; /* use Toeplitz hash */
} basicvirtual;
} u;
};
@@ -151,11 +151,11 @@ struct rss_params {
union rss_vi_config {
struct {
u16 defaultq; /* Ingress Queue ID for !tnlalllookup */
- unsigned int ip6fourtupen:1; /* hash 4-tuple IPv6 ingress packets */
- unsigned int ip6twotupen:1; /* hash 2-tuple IPv6 ingress packets */
- unsigned int ip4fourtupen:1; /* hash 4-tuple IPv4 ingress packets */
- unsigned int ip4twotupen:1; /* hash 2-tuple IPv4 ingress packets */
- int udpen; /* hash 4-tuple UDP ingress packets */
+ uint ip6fourtupen:1; /* hash 4-tuple IPv6 ingress packets */
+ uint ip6twotupen:1; /* hash 2-tuple IPv6 ingress packets */
+ uint ip4fourtupen:1; /* hash 4-tuple IPv4 ingress packets */
+ uint ip4twotupen:1; /* hash 2-tuple IPv4 ingress packets */
+ uint udpen:1; /* hash 4-tuple UDP ingress packets */
} basicvirtual;
};
--
1.7.0.4
^ permalink raw reply related
* [PATCH 10/10] cxgb4vf: add call to Firmware to reset VF State.
From: Casey Leedom @ 2010-11-11 2:04 UTC (permalink / raw)
To: netdev; +Cc: davem, Casey Leedom
In-Reply-To: <450C6E98-D0D9-42A6-9F15-4DB98647DB04@chelsio.com>
Add call to Firmware to reset its VF State when we first attach to the VF.
Signed-off-by: Casey Leedom <leedom@chelsio.com>
---
drivers/net/cxgb4vf/cxgb4vf_main.c | 16 ++++++++++++++++
drivers/net/cxgb4vf/t4vf_common.h | 1 +
drivers/net/cxgb4vf/t4vf_hw.c | 19 +++++++++++++++++++
3 files changed, 36 insertions(+), 0 deletions(-)
diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c
index 15b14ef..3456a9b 100644
--- a/drivers/net/cxgb4vf/cxgb4vf_main.c
+++ b/drivers/net/cxgb4vf/cxgb4vf_main.c
@@ -2076,6 +2076,22 @@ static int __devinit adap_init0(struct adapter *adapter)
}
/*
+ * Some environments do not properly handle PCIE FLRs -- e.g. in Linux
+ * 2.6.31 and later we can't call pci_reset_function() in order to
+ * issue an FLR because of a self- deadlock on the device semaphore.
+ * Meanwhile, the OS infrastructure doesn't issue FLRs in all the
+ * cases where they're needed -- for instance, some versions of KVM
+ * fail to reset "Assigned Devices" when the VM reboots. Therefore we
+ * use the firmware based reset in order to reset any per function
+ * state.
+ */
+ err = t4vf_fw_reset(adapter);
+ if (err < 0) {
+ dev_err(adapter->pdev_dev, "FW reset failed: err=%d\n", err);
+ return err;
+ }
+
+ /*
* Grab basic operational parameters. These will predominantly have
* been set up by the Physical Function Driver or will be hard coded
* into the adapter. We just have to live with them ... Note that
diff --git a/drivers/net/cxgb4vf/t4vf_common.h b/drivers/net/cxgb4vf/t4vf_common.h
index 659616b..7541a60 100644
--- a/drivers/net/cxgb4vf/t4vf_common.h
+++ b/drivers/net/cxgb4vf/t4vf_common.h
@@ -235,6 +235,7 @@ static inline int t4vf_wr_mbox_ns(struct adapter *adapter, const void *cmd,
int __devinit t4vf_wait_dev_ready(struct adapter *);
int __devinit t4vf_port_init(struct adapter *, int);
+int t4vf_fw_reset(struct adapter *);
int t4vf_query_params(struct adapter *, unsigned int, const u32 *, u32 *);
int t4vf_set_params(struct adapter *, unsigned int, const u32 *, const u32 *);
diff --git a/drivers/net/cxgb4vf/t4vf_hw.c b/drivers/net/cxgb4vf/t4vf_hw.c
index 2180181..591f161 100644
--- a/drivers/net/cxgb4vf/t4vf_hw.c
+++ b/drivers/net/cxgb4vf/t4vf_hw.c
@@ -326,6 +326,25 @@ int __devinit t4vf_port_init(struct adapter *adapter, int pidx)
}
/**
+ * t4vf_fw_reset - issue a reset to FW
+ * @adapter: the adapter
+ *
+ * Issues a reset command to FW. For a Physical Function this would
+ * result in the Firmware reseting all of its state. For a Virtual
+ * Function this just resets the state associated with the VF.
+ */
+int t4vf_fw_reset(struct adapter *adapter)
+{
+ struct fw_reset_cmd cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.op_to_write = cpu_to_be32(FW_CMD_OP(FW_RESET_CMD) |
+ FW_CMD_WRITE);
+ cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
+ return t4vf_wr_mbox(adapter, &cmd, sizeof(cmd), NULL);
+}
+
+/**
* t4vf_query_params - query FW or device parameters
* @adapter: the adapter
* @nparams: the number of parameters
--
1.7.0.4
^ permalink raw reply related
* Re: [PATCH 01/10] cxgb4vf: minor comment/symbolic name cleanup.
From: Joe Perches @ 2010-11-11 3:19 UTC (permalink / raw)
To: Casey Leedom; +Cc: netdev, davem
In-Reply-To: <1289441052-4925-1-git-send-email-leedom@chelsio.com>
On Wed, 2010-11-10 at 18:04 -0800, Casey Leedom wrote:
> Minor cleanup of comments and symbolic constant names for clarity.
> diff --git a/drivers/net/cxgb4vf/cxgb4vf_main.c b/drivers/net/cxgb4vf/cxgb4vf_main.c
> index 6de5e2e..f5259a1 100644
> --- a/drivers/net/cxgb4vf/cxgb4vf_main.c
> +++ b/drivers/net/cxgb4vf/cxgb4vf_main.c
> @@ -280,7 +280,7 @@ static void name_msix_vecs(struct adapter *adapter)
> const struct port_info *pi = netdev_priv(dev);
> int qs, msi;
>
> - for (qs = 0, msi = MSIX_NIQFLINT;
> + for (qs = 0, msi = MSIX_IQFLINT;
> qs < pi->nqsets;
> qs++, msi++) {
This for now fits on a single line.
> diff --git a/drivers/net/cxgb4vf/t4vf_hw.c b/drivers/net/cxgb4vf/t4vf_hw.c
> index ea1c123..2180181 100644
> --- a/drivers/net/cxgb4vf/t4vf_hw.c
> +++ b/drivers/net/cxgb4vf/t4vf_hw.c
> @@ -1257,7 +1257,7 @@ int t4vf_eth_eq_free(struct adapter *adapter, unsigned int eqid)
> */
> int t4vf_handle_fw_rpl(struct adapter *adapter, const __be64 *rpl)
> - struct fw_cmd_hdr *cmd_hdr = (struct fw_cmd_hdr *)rpl;
> + const struct fw_cmd_hdr *cmd_hdr = (const struct fw_cmd_hdr *)rpl;
> @@ -1265,7 +1265,7 @@ int t4vf_handle_fw_rpl(struct adapter *adapter, const __be64 *rpl)
> - const struct fw_port_cmd *port_cmd = (void *)rpl;
> + const struct fw_port_cmd *port_cmd = (const void *)rpl;
might be better to have a consistent casting style.
1st uses a direct cast, 2nd an implicit one.
^ permalink raw reply
* [PATCH] drivers/isdn/hisax: Add printf format/argument verification and fix fallout
From: Joe Perches @ 2010-11-11 4:54 UTC (permalink / raw)
To: linux-kernel; +Cc: Karsten Keil, netdev
Add __attribute__((format... to several functins
Make formats and arguments match.
Signed-off-by: Joe Perches <joe@perches.com>
---
drivers/isdn/hisax/avm_pci.c | 2 +-
drivers/isdn/hisax/callc.c | 4 ++--
drivers/isdn/hisax/hfc_2bds0.c | 4 ++--
drivers/isdn/hisax/hfc_2bs0.c | 2 +-
drivers/isdn/hisax/hfc_pci.c | 4 ++--
drivers/isdn/hisax/hfc_sx.c | 6 +++---
drivers/isdn/hisax/hisax.h | 2 ++
drivers/isdn/hisax/ipacx.c | 2 +-
drivers/isdn/hisax/isar.c | 6 +++---
drivers/isdn/hisax/isdnl1.h | 1 +
drivers/isdn/hisax/isdnl3.c | 2 +-
drivers/isdn/hisax/netjet.c | 10 +++++-----
drivers/isdn/hisax/st5481_d.c | 6 ++++--
13 files changed, 28 insertions(+), 23 deletions(-)
diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c
index fcf4ed1..0e66af1 100644
--- a/drivers/isdn/hisax/avm_pci.c
+++ b/drivers/isdn/hisax/avm_pci.c
@@ -314,7 +314,7 @@ hdlc_fill_fifo(struct BCState *bcs)
bcs->hw.hdlc.ctrl.sr.cmd |= HDLC_CMD_XME;
}
if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
- debugl1(cs, "hdlc_fill_fifo %d/%ld", count, bcs->tx_skb->len);
+ debugl1(cs, "hdlc_fill_fifo %d/%u", count, bcs->tx_skb->len);
p = bcs->tx_skb->data;
ptr = (u_int *)p;
skb_pull(bcs->tx_skb, count);
diff --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c
index f150330..37e685e 100644
--- a/drivers/isdn/hisax/callc.c
+++ b/drivers/isdn/hisax/callc.c
@@ -65,7 +65,7 @@ hisax_findcard(int driverid)
return (struct IsdnCardState *) 0;
}
-static void
+static __attribute__((format(printf, 3, 4))) void
link_debug(struct Channel *chanp, int direction, char *fmt, ...)
{
va_list args;
@@ -1068,7 +1068,7 @@ init_d_st(struct Channel *chanp)
return 0;
}
-static void
+static __attribute__((format(printf, 2, 3))) void
callc_debug(struct FsmInst *fi, char *fmt, ...)
{
va_list args;
diff --git a/drivers/isdn/hisax/hfc_2bds0.c b/drivers/isdn/hisax/hfc_2bds0.c
index 7250f56..a16459a 100644
--- a/drivers/isdn/hisax/hfc_2bds0.c
+++ b/drivers/isdn/hisax/hfc_2bds0.c
@@ -292,7 +292,7 @@ hfc_fill_fifo(struct BCState *bcs)
}
count = GetFreeFifoBytes_B(bcs);
if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfc_fill_fifo %d count(%ld/%d),%lx",
+ debugl1(cs, "hfc_fill_fifo %d count(%u/%d),%lx",
bcs->channel, bcs->tx_skb->len,
count, current->state);
if (count < bcs->tx_skb->len) {
@@ -719,7 +719,7 @@ hfc_fill_dfifo(struct IsdnCardState *cs)
}
count = GetFreeFifoBytes_D(cs);
if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "hfc_fill_Dfifo count(%ld/%d)",
+ debugl1(cs, "hfc_fill_Dfifo count(%u/%d)",
cs->tx_skb->len, count);
if (count < cs->tx_skb->len) {
if (cs->debug & L1_DEB_ISAC)
diff --git a/drivers/isdn/hisax/hfc_2bs0.c b/drivers/isdn/hisax/hfc_2bs0.c
index b1f6481..626f85d 100644
--- a/drivers/isdn/hisax/hfc_2bs0.c
+++ b/drivers/isdn/hisax/hfc_2bs0.c
@@ -282,7 +282,7 @@ hfc_fill_fifo(struct BCState *bcs)
count += cs->hw.hfc.fifosize;
} /* L1_MODE_TRANS */
if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfc_fill_fifo %d count(%ld/%d)",
+ debugl1(cs, "hfc_fill_fifo %d count(%u/%d)",
bcs->channel, bcs->tx_skb->len,
count);
if (count < bcs->tx_skb->len) {
diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c
index 917cc84..3147020 100644
--- a/drivers/isdn/hisax/hfc_pci.c
+++ b/drivers/isdn/hisax/hfc_pci.c
@@ -550,7 +550,7 @@ hfcpci_fill_dfifo(struct IsdnCardState *cs)
count += D_FIFO_SIZE; /* count now contains available bytes */
if (cs->debug & L1_DEB_ISAC)
- debugl1(cs, "hfcpci_fill_Dfifo count(%ld/%d)",
+ debugl1(cs, "hfcpci_fill_Dfifo count(%u/%d)",
cs->tx_skb->len, count);
if (count < cs->tx_skb->len) {
if (cs->debug & L1_DEB_ISAC)
@@ -681,7 +681,7 @@ hfcpci_fill_fifo(struct BCState *bcs)
count += B_FIFO_SIZE; /* count now contains available bytes */
if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "hfcpci_fill_fifo %d count(%ld/%d),%lx",
+ debugl1(cs, "hfcpci_fill_fifo %d count(%u/%d),%lx",
bcs->channel, bcs->tx_skb->len,
count, current->state);
diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c
index 5aa138e..1235b71 100644
--- a/drivers/isdn/hisax/hfc_sx.c
+++ b/drivers/isdn/hisax/hfc_sx.c
@@ -179,7 +179,7 @@ write_fifo(struct IsdnCardState *cs, struct sk_buff *skb, u_char fifo, int trans
count += fifo_size; /* count now contains available bytes */
if (cs->debug & L1_DEB_ISAC_FIFO)
- debugl1(cs, "hfcsx_write_fifo %d count(%ld/%d)",
+ debugl1(cs, "hfcsx_write_fifo %d count(%u/%d)",
fifo, skb->len, count);
if (count < skb->len) {
if (cs->debug & L1_DEB_ISAC_FIFO)
@@ -265,7 +265,7 @@ read_fifo(struct IsdnCardState *cs, u_char fifo, int trans_max)
count++;
if (cs->debug & L1_DEB_ISAC_FIFO)
- debugl1(cs, "hfcsx_read_fifo %d count %ld)",
+ debugl1(cs, "hfcsx_read_fifo %d count %u)",
fifo, count);
if ((count > fifo_size) || (count < 4)) {
@@ -986,7 +986,7 @@ HFCSX_l1hw(struct PStack *st, int pr, void *arg)
default:
spin_unlock_irqrestore(&cs->lock, flags);
if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "hfcsx_l1hw loop invalid %4lx", arg);
+ debugl1(cs, "hfcsx_l1hw loop invalid %4lx", (unsigned long)arg);
return;
}
cs->hw.hfcsx.trm |= 0x80; /* enable IOM-loop */
diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
index 32ab392..de1c669 100644
--- a/drivers/isdn/hisax/hisax.h
+++ b/drivers/isdn/hisax/hisax.h
@@ -1286,7 +1286,9 @@ int jiftime(char *s, long mark);
int HiSax_command(isdn_ctrl * ic);
int HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb);
+__attribute__((format(printf, 3, 4)))
void HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...);
+__attribute__((format(printf, 3, 0)))
void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, va_list args);
void HiSax_reportcard(int cardnr, int sel);
int QuickHex(char *txt, u_char * p, int cnt);
diff --git a/drivers/isdn/hisax/ipacx.c b/drivers/isdn/hisax/ipacx.c
index 751b25f..3321041 100644
--- a/drivers/isdn/hisax/ipacx.c
+++ b/drivers/isdn/hisax/ipacx.c
@@ -717,7 +717,7 @@ bch_mode(struct BCState *bcs, int mode, int bc)
bc = bc ? 1 : 0; // in case bc is greater than 1
if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "mode_bch() switch B-% mode %d chan %d", hscx, mode, bc);
+ debugl1(cs, "mode_bch() switch B-%d mode %d chan %d", hscx, mode, bc);
bcs->mode = mode;
bcs->channel = bc;
diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c
index 2e72227..1be4552 100644
--- a/drivers/isdn/hisax/isar.c
+++ b/drivers/isdn/hisax/isar.c
@@ -953,7 +953,7 @@ isar_pump_statev_modem(struct BCState *bcs, u_char devt) {
break;
case PSEV_GSTN_CLR:
if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "pump stev GSTN CLEAR", devt);
+ debugl1(cs, "pump stev GSTN CLEAR");
break;
default:
if (cs->debug & L1_DEB_HSCX)
@@ -1268,7 +1268,7 @@ isar_int_main(struct IsdnCardState *cs)
static void
ftimer_handler(struct BCState *bcs) {
if (bcs->cs->debug)
- debugl1(bcs->cs, "ftimer flags %04x",
+ debugl1(bcs->cs, "ftimer flags %04lx",
bcs->Flag);
test_and_clear_bit(BC_FLG_FTI_RUN, &bcs->Flag);
if (test_and_clear_bit(BC_FLG_LL_CONN, &bcs->Flag)) {
@@ -1748,7 +1748,7 @@ isar_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) {
struct BCState *bcs;
if (cs->debug & L1_DEB_HSCX)
- debugl1(cs, "isar_auxcmd cmd/ch %x/%d", ic->command, ic->arg);
+ debugl1(cs, "isar_auxcmd cmd/ch %x/%ld", ic->command, ic->arg);
switch (ic->command) {
case (ISDN_CMD_FAXCMD):
bcs = cs->channel[ic->arg].bcs;
diff --git a/drivers/isdn/hisax/isdnl1.h b/drivers/isdn/hisax/isdnl1.h
index 172ad4c..425d861 100644
--- a/drivers/isdn/hisax/isdnl1.h
+++ b/drivers/isdn/hisax/isdnl1.h
@@ -21,6 +21,7 @@
#define B_XMTBUFREADY 1
#define B_ACKPENDING 2
+__attribute__((format(printf, 2, 3)))
void debugl1(struct IsdnCardState *cs, char *fmt, ...);
void DChannel_proc_xmt(struct IsdnCardState *cs);
void DChannel_proc_rcv(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/isdnl3.c b/drivers/isdn/hisax/isdnl3.c
index fd0b643..ad291f2 100644
--- a/drivers/isdn/hisax/isdnl3.c
+++ b/drivers/isdn/hisax/isdnl3.c
@@ -66,7 +66,7 @@ static char *strL3Event[] =
"EV_TIMEOUT",
};
-static void
+static __attribute__((format(printf, 2, 3))) void
l3m_debug(struct FsmInst *fi, char *fmt, ...)
{
va_list args;
diff --git a/drivers/isdn/hisax/netjet.c b/drivers/isdn/hisax/netjet.c
index 5d7f0f2..644891e 100644
--- a/drivers/isdn/hisax/netjet.c
+++ b/drivers/isdn/hisax/netjet.c
@@ -254,7 +254,7 @@ static int make_raw_data(struct BCState *bcs) {
val >>= 1;
}
if (bcs->cs->debug & L1_DEB_HSCX)
- debugl1(bcs->cs,"tiger make_raw: in %ld out %d.%d",
+ debugl1(bcs->cs,"tiger make_raw: in %u out %d.%d",
bcs->tx_skb->len, s_cnt, bitcnt);
if (bitcnt) {
while (8>bitcnt++) {
@@ -361,7 +361,7 @@ static int make_raw_data_56k(struct BCState *bcs) {
val >>= 1;
}
if (bcs->cs->debug & L1_DEB_HSCX)
- debugl1(bcs->cs,"tiger make_raw_56k: in %ld out %d.%d",
+ debugl1(bcs->cs,"tiger make_raw_56k: in %u out %d.%d",
bcs->tx_skb->len, s_cnt, bitcnt);
if (bitcnt) {
while (8>bitcnt++) {
@@ -612,7 +612,7 @@ void netjet_fill_dma(struct BCState *bcs)
if (!bcs->tx_skb)
return;
if (bcs->cs->debug & L1_DEB_HSCX)
- debugl1(bcs->cs,"tiger fill_dma1: c%d %4x", bcs->channel,
+ debugl1(bcs->cs,"tiger fill_dma1: c%d %4lx", bcs->channel,
bcs->Flag);
if (test_and_set_bit(BC_FLG_BUSY, &bcs->Flag))
return;
@@ -625,7 +625,7 @@ void netjet_fill_dma(struct BCState *bcs)
return;
};
if (bcs->cs->debug & L1_DEB_HSCX)
- debugl1(bcs->cs,"tiger fill_dma2: c%d %4x", bcs->channel,
+ debugl1(bcs->cs,"tiger fill_dma2: c%d %4lx", bcs->channel,
bcs->Flag);
if (test_and_clear_bit(BC_FLG_NOFRAME, &bcs->Flag)) {
write_raw(bcs, bcs->hw.tiger.sendp, bcs->hw.tiger.free);
@@ -667,7 +667,7 @@ void netjet_fill_dma(struct BCState *bcs)
write_raw(bcs, p, cnt);
}
if (bcs->cs->debug & L1_DEB_HSCX)
- debugl1(bcs->cs,"tiger fill_dma3: c%d %4x", bcs->channel,
+ debugl1(bcs->cs,"tiger fill_dma3: c%d %4lx", bcs->channel,
bcs->Flag);
}
diff --git a/drivers/isdn/hisax/st5481_d.c b/drivers/isdn/hisax/st5481_d.c
index b7876b1..4408263 100644
--- a/drivers/isdn/hisax/st5481_d.c
+++ b/drivers/isdn/hisax/st5481_d.c
@@ -167,7 +167,8 @@ static struct FsmNode L1FnList[] __initdata =
{ST_L1_F8, EV_IND_RSY, l1_ignore},
};
-static void l1m_debug(struct FsmInst *fi, char *fmt, ...)
+static __attribute__((format(printf, 2, 3)))
+void l1m_debug(struct FsmInst *fi, char *fmt, ...)
{
va_list args;
char buf[256];
@@ -269,7 +270,8 @@ static char *strDoutEvent[] =
"EV_DOUT_UNDERRUN",
};
-static void dout_debug(struct FsmInst *fi, char *fmt, ...)
+static __attribute__((format(printf, 2, 3)))
+void dout_debug(struct FsmInst *fi, char *fmt, ...)
{
va_list args;
char buf[256];
--
1.7.3.1.g432b3.dirty
^ permalink raw reply related
* Re: possible kernel oops from user MSS
From: Shan Wei @ 2010-11-11 5:15 UTC (permalink / raw)
To: David Miller; +Cc: schen, netdev
In-Reply-To: <20101110.124119.102563803.davem@davemloft.net>
David Miller wrote, at 11/11/2010 04:41 AM:
> From: Steve Chen <schen@mvista.com>
> Date: Wed, 10 Nov 2010 07:24:51 -0600
>
>> With commit f5fff5dc8a7a3f395b0525c02ba92c95d42b7390, a user program
>> can pass in TCP_MAXSEG of 12 (or TCPOLEN_TSTAMP_ALIGNED), and cause
>> kernel oops with division by 0
>> in tcp_select_initial_window. One way to prevent it is to change the
>> minimum value for TCP_MAXSEG in do_tcp_setsockopt from 8 to some value
>> over 12. Two questions.
>>
>> 1. Is this the right solution?
>> 2. If it is, what is a good minimum value?
>
> Thanks Steve, I'll fix this like so:
>
> --------------------
> tcp: Increase TCP_MAXSEG socket option minimum.
>
> As noted by Steve Chen, since commit
> f5fff5dc8a7a3f395b0525c02ba92c95d42b7390 ("tcp: advertise MSS
> requested by user") we can end up with a situation where
> tcp_select_initial_window() does a divide by a zero (or
> even negative) mss value.
>
> The problem is that sometimes we subtract TCPOLEN_TSTAMP_ALIGNED
> from the mss.
>
> Fix this by increasing the minimum from 8 to 8 plus the value
> of TCPOLEN_TSTATMP_ALIGNED.
In tcp_connect_init(), if tcp_header_len includes TCPOLEN_TSTAMP_ALIGNED(12 bytes)
and TCPOLEN_MD5SIG_ALIGNED(20 bytes).
This fix is still not perfect.
The minimum value of TCP_MAXSEG is 20 tytes, tcp_select_initial_window() still be
called with negative mss value.
--
Best Regards
-----
Shan Wei
> Reported-by: Steve Chen <schen@mvista.com>
> Signed-off-by: David S. Miller <davem@davemloft.net>
> ---
> net/ipv4/tcp.c | 2 +-
> 1 files changed, 1 insertions(+), 1 deletions(-)
>
> diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
> index 245603c..6b0eb4d 100644
> --- a/net/ipv4/tcp.c
> +++ b/net/ipv4/tcp.c
> @@ -2246,7 +2246,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
> /* Values greater than interface MTU won't take effect. However
> * at the point when this call is done we typically don't yet
> * know which interface is going to be used */
> - if (val < 8 || val > MAX_TCP_WINDOW) {
> + if (val < TCPOLEN_TSTAMP_ALIGNED + 8 || val > MAX_TCP_WINDOW) {
> err = -EINVAL;
> break;
> }
^ permalink raw reply
* Re: possible kernel oops from user MSS
From: David Miller @ 2010-11-11 5:33 UTC (permalink / raw)
To: shanwei; +Cc: schen, netdev
In-Reply-To: <4CDB7BD5.6030204@cn.fujitsu.com>
From: Shan Wei <shanwei@cn.fujitsu.com>
Date: Thu, 11 Nov 2010 13:15:01 +0800
> In tcp_connect_init(), if tcp_header_len includes TCPOLEN_TSTAMP_ALIGNED(12 bytes)
> and TCPOLEN_MD5SIG_ALIGNED(20 bytes).
If you knew this, why didn't you mention it in your initial report? :-/
I'll make the minimum 64 or something like that.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox