Commit 02c958dd authored by Cyrille Pitchen's avatar Cyrille Pitchen Committed by David S. Miller

net/macb: add TX multiqueue support for gem

gem devices designed with multiqueue CANNOT work without this patch.

When probing a gem device, the driver must first prepare and enable the
peripheral clock before accessing I/O registers. The second step is to read the
MID register to find whether the device is a gem or an old macb IP.
For gem devices, it reads the Design Configuration Register 6 (DCFG6) to
compute to total number of queues, whereas macb devices always have a single
queue.
Only then it can call alloc_etherdev_mq() with the correct number of queues.
This is the reason why the order of some initializations has been changed in
macb_probe().
Eventually, the dedicated IRQ and TX ring buffer descriptors are initialized
for each queue.

For backward compatibility reasons, queue0 uses the legacy registers ISR, IER,
IDR, IMR, TBQP and RBQP. On the other hand, the other queues use new registers
ISR[1..7], IER[1..7], IDR[1..7], IMR[1..7], TBQP[1..7] and RBQP[1..7].
Except this hardware detail there is no real difference between queue0 and the
others. The driver hides that thanks to the struct macb_queue.
This structure allows us to share a common set of functions for all the queues.

Besides when a TX error occurs, the gem MUST be halted before writing any of
the TBQP registers to reset the relevant queue. An immediate side effect is
that the other queues too aren't processed anymore by the gem.
So macb_tx_error_task() calls netif_tx_stop_all_queues() to notify the Linux
network engine that all transmissions are stopped.

Also macb_tx_error_task() now calls spin_lock_irqsave() to prevent the
interrupt handlers of the other queues from running as each of them may wake
its associated queue up (please refer to macb_tx_interrupt()).

Finally, as all queues have previously been stopped, they should be restarted
calling netif_tx_start_all_queues() and setting the TSTART bit into the Network
Control Register. Before this patch, when dealing with a single queue, the
driver used to defer the reset of the faulting queue and the write of the
TSTART bit until the next call of macb_start_xmit().
As explained before, this bit is now set by macb_tx_error_task() too. That's
why the faulting queue MUST be reset by setting the TX_USED bit in its first
buffer descriptor before writing the TSTART bit.

Queue 0 always exits and is the lowest priority when other queues are available.
The higher the index of the queue is, the higher its priority is.

When transmitting frames, the TX queue is selected by the skb->queue_mapping
value. So queue discipline can be used to define the queue priority policy.
Signed-off-by: default avatarCyrille Pitchen <cyrille.pitchen@atmel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d717e904
This diff is collapsed.
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#define MACB_GREGS_NBR 16 #define MACB_GREGS_NBR 16
#define MACB_GREGS_VERSION 1 #define MACB_GREGS_VERSION 1
#define MACB_MAX_QUEUES 8
/* MACB register offsets */ /* MACB register offsets */
#define MACB_NCR 0x0000 #define MACB_NCR 0x0000
...@@ -89,6 +90,13 @@ ...@@ -89,6 +90,13 @@
#define GEM_DCFG6 0x0294 #define GEM_DCFG6 0x0294
#define GEM_DCFG7 0x0298 #define GEM_DCFG7 0x0298
#define GEM_ISR(hw_q) (0x0400 + ((hw_q) << 2))
#define GEM_TBQP(hw_q) (0x0440 + ((hw_q) << 2))
#define GEM_RBQP(hw_q) (0x0480 + ((hw_q) << 2))
#define GEM_IER(hw_q) (0x0600 + ((hw_q) << 2))
#define GEM_IDR(hw_q) (0x0620 + ((hw_q) << 2))
#define GEM_IMR(hw_q) (0x0640 + ((hw_q) << 2))
/* Bitfields in NCR */ /* Bitfields in NCR */
#define MACB_LB_OFFSET 0 #define MACB_LB_OFFSET 0
#define MACB_LB_SIZE 1 #define MACB_LB_SIZE 1
...@@ -376,6 +384,10 @@ ...@@ -376,6 +384,10 @@
__raw_readl((port)->regs + GEM_##reg) __raw_readl((port)->regs + GEM_##reg)
#define gem_writel(port, reg, value) \ #define gem_writel(port, reg, value) \
__raw_writel((value), (port)->regs + GEM_##reg) __raw_writel((value), (port)->regs + GEM_##reg)
#define queue_readl(queue, reg) \
__raw_readl((queue)->bp->regs + (queue)->reg)
#define queue_writel(queue, reg, value) \
__raw_writel((value), (queue)->bp->regs + (queue)->reg)
/* /*
* Conditional GEM/MACB macros. These perform the operation to the correct * Conditional GEM/MACB macros. These perform the operation to the correct
...@@ -597,6 +609,23 @@ struct macb_config { ...@@ -597,6 +609,23 @@ struct macb_config {
unsigned int dma_burst_length; unsigned int dma_burst_length;
}; };
struct macb_queue {
struct macb *bp;
int irq;
unsigned int ISR;
unsigned int IER;
unsigned int IDR;
unsigned int IMR;
unsigned int TBQP;
unsigned int tx_head, tx_tail;
struct macb_dma_desc *tx_ring;
struct macb_tx_skb *tx_skb;
dma_addr_t tx_ring_dma;
struct work_struct tx_error_task;
};
struct macb { struct macb {
void __iomem *regs; void __iomem *regs;
...@@ -607,9 +636,8 @@ struct macb { ...@@ -607,9 +636,8 @@ struct macb {
void *rx_buffers; void *rx_buffers;
size_t rx_buffer_size; size_t rx_buffer_size;
unsigned int tx_head, tx_tail; unsigned int num_queues;
struct macb_dma_desc *tx_ring; struct macb_queue queues[MACB_MAX_QUEUES];
struct macb_tx_skb *tx_skb;
spinlock_t lock; spinlock_t lock;
struct platform_device *pdev; struct platform_device *pdev;
...@@ -618,7 +646,6 @@ struct macb { ...@@ -618,7 +646,6 @@ struct macb {
struct clk *tx_clk; struct clk *tx_clk;
struct net_device *dev; struct net_device *dev;
struct napi_struct napi; struct napi_struct napi;
struct work_struct tx_error_task;
struct net_device_stats stats; struct net_device_stats stats;
union { union {
struct macb_stats macb; struct macb_stats macb;
...@@ -626,7 +653,6 @@ struct macb { ...@@ -626,7 +653,6 @@ struct macb {
} hw_stats; } hw_stats;
dma_addr_t rx_ring_dma; dma_addr_t rx_ring_dma;
dma_addr_t tx_ring_dma;
dma_addr_t rx_buffers_dma; dma_addr_t rx_buffers_dma;
struct macb_or_gem_ops macbgem_ops; struct macb_or_gem_ops macbgem_ops;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment