diff options
author | Sandeep Paulraj <s-paulraj@ti.com> | 2012-09-17 12:41:28 -0400 |
---|---|---|
committer | Cyril Chemparathy <cyril@ti.com> | 2012-09-21 10:44:12 -0400 |
commit | 1a3261fa98b39f283c318024d58469891979fa0b (patch) | |
tree | 65cff815fd0ecddf5186134763b007dbd93f7b36 | |
parent | 3e3cf16d08ccdba7cc213d004b42340f47dc12a9 (diff) | |
download | linux-keystone-1a3261fa98b39f283c318024d58469891979fa0b.tar.gz |
dma: keystone: add support for more than 4096 queues
The existing implementation of the keystone dma engine prevented queues
above 4095 from being used. This commit adds support in the keystone dma
engine to enable queues greater than 4095 to be used.
Any queue from 4096 to 8192 logically belongs to another queue manager.
So based on the queue number we calculate the queue manager number.
The existing implementation was never writing the queue manager number into
the appropriate locations in the descriptor and the packet dma rx flow
register. At reset this value was zero and things worked. While using any
queue above 4095, we have to appropriatley calculate the queue manager number
and put it in the descriptor and the appropriate packet dma rx flow register.
Also, the driver was not modifying the qm_base_address registers in the
global packet dma control registers. Again on reset, the appropriate value is
set into QM0 base address register and the others are 0. This also prevents
queues greater than 4095 from being used. To this effect, device tree support
is being added. We can have a maximum of 4 logical queue managers but in the
current generation of devices we have 2. From device tree we apprise the
driver of the number of queue managers using the binding
logical-queue-managers. In the device tree we also define the
qm-base-address for each logical queue manager using an array.
Signed-off-by: Sandeep Paulraj <s-paulraj@ti.com>
-rw-r--r-- | Documentation/devicetree/bindings/dma/keystone-pktdma.txt | 51 | ||||
-rw-r--r-- | drivers/dma/keystone-pktdma.c | 46 |
2 files changed, 55 insertions, 42 deletions
diff --git a/Documentation/devicetree/bindings/dma/keystone-pktdma.txt b/Documentation/devicetree/bindings/dma/keystone-pktdma.txt index f367b2ce8ee3a3..d82e6a09dcea71 100644 --- a/Documentation/devicetree/bindings/dma/keystone-pktdma.txt +++ b/Documentation/devicetree/bindings/dma/keystone-pktdma.txt @@ -37,49 +37,15 @@ channel: the actual channel number to be used. priority: the priority associated with a channel. flow: the RX flow that will be used. Applicable only for RX. +logical-queue-managers: number of logical queue managers +queues-per-queue-manager: the number of queues per queue manager +qm-base-address: the actual VBUSM address that needs to be programmed into + each QM_BASE_ADDR register. The number of distinct values + should be equal to the number of logical queue managers. -2 examples are provided below. infradma is the packet dma instance associated -with the queue manage susbsystem. padma is packet dma instance associated +An examples is provided below. padma is packet dma instance associated with the packet accelerator susbsystem. -infradma: pktdma@2a6c000 { - compatible = "ti,keystone-pktdma"; - reg = <0x2a6c000 0x100 /* 0 - global */ - 0x2a6c400 0x400 /* 1 - txchan */ - 0x2a6c800 0x400 /* 2 - rxchan */ - 0x2a6cc00 0x400 /* 3 - txsched */ - 0x2a6d000 0x400>; /* 4 - rxflow */ - loop-back; - /* big-endian; */ - /* enable-all; */ - /* debug; */ - channels { - vethtx { - transmit; - label = "vethtx"; - pool = "pool-veth"; - descriptors = <128>; - submit-queue = <800>; - /* complete-queue = <xx>; */ - /* debug; */ - channel = <0>; - priority = <1>; - flowtag = <1>; - }; - vethrx { - receive; - label = "vethrx"; - pool = "pool-veth"; - descriptors = <128>; - /* submit-queue = <xx>; */ - /* complete-queue = <xx>; */ - /* debug; */ - channel = <0>; - flow = <0>; - }; - }; - }; - padma: pktdma@2004000 { compatible = "ti,keystone-pktdma"; reg = <0x2004000 0x100 /* 0 - global */ @@ -91,6 +57,11 @@ infradma: pktdma@2a6c000 { /* bigendian; */ enable-all; /* debug; */ + + logical-queue-managers = <2>; + queues-per-queue-manager = <4096>; + qm-base-address = <0x34020000 0x34030000>; + channels { nettx { transmit; diff --git a/drivers/dma/keystone-pktdma.c b/drivers/dma/keystone-pktdma.c index a3fd6cb679baac..a7f9e609e71057 100644 --- a/drivers/dma/keystone-pktdma.c +++ b/drivers/dma/keystone-pktdma.c @@ -50,6 +50,7 @@ #define DESC_PSFLAGS_SHIFT 16 #define DESC_RETQ_MASK BITS(14) #define DESC_RETQ_SHIFT 0 +#define DESC_RETQMGR_SHIFT 12 #define DESC_FLOWTAG_MASK BITS(8) #define DESC_FLOWTAG_SHIFT 16 #define DESC_LEN_MASK BITS(22) @@ -158,6 +159,9 @@ struct keystone_dma_device { struct clk *clk; bool big_endian, loopback, enable_all; unsigned tx_priority, rx_priority; + unsigned logical_queue_managers; + unsigned queues_per_queue_manager; + unsigned qm_base_address[4]; struct reg_global __iomem *reg_global; struct reg_chan __iomem *reg_tx_chan; struct reg_rx_flow __iomem *reg_rx_flow; @@ -197,6 +201,7 @@ struct keystone_dma_chan { void *descs; int qnum_submit[KEYSTONE_QUEUES_PER_CHAN]; int qnum_complete; + int dest_queue_manager; struct dma_notify_info notify_info; wait_queue_head_t state_wait_queue; @@ -767,6 +772,7 @@ static void chan_destroy_queues(struct keystone_dma_chan *chan) } chan->q_complete = NULL; chan->qnum_complete = 0; + chan->dest_queue_manager = 0; for (i = 0; i < KEYSTONE_QUEUES_PER_CHAN; ++i) { if (chan->q_submit[i]) @@ -782,6 +788,7 @@ static void chan_destroy_queues(struct keystone_dma_chan *chan) static int chan_setup_queues(struct keystone_dma_chan *chan) { + struct keystone_dma_device *dma = chan->dma; unsigned flags = O_RDWR; struct hwqueue *q; int ret = 0; @@ -834,6 +841,8 @@ static int chan_setup_queues(struct keystone_dma_chan *chan) } chan->qnum_complete = hwqueue_get_id(q); chan->q_complete = q; + chan->dest_queue_manager = chan->qnum_complete / + dma->queues_per_queue_manager; /* setup queue notifier */ ret = hwqueue_set_notifier(q, chan_complete_callback, chan); @@ -876,7 +885,9 @@ static int chan_start(struct keystone_dma_chan *chan) if (chan->reg_rx_flow) { v = CHAN_HAS_EPIB | CHAN_HAS_PSINFO; - v |= chan->qnum_complete | (DESC_TYPE_HOST << DESC_TYPE_SHIFT); + v |= chan->qnum_complete | + (chan->dest_queue_manager << DESC_RETQMGR_SHIFT) | + (DESC_TYPE_HOST << DESC_TYPE_SHIFT); __raw_writel(v, &chan->reg_rx_flow->control); __raw_writel(0, &chan->reg_rx_flow->tags); @@ -1154,6 +1165,10 @@ static void keystone_dma_hw_init(struct keystone_dma_device *dma) } } + for (i = 0; i < dma->logical_queue_managers; i++) + __raw_writel(dma->qm_base_address[i], + &dma->reg_global->qm_base_address[i]); + } static void keystone_dma_hw_destroy(struct keystone_dma_device *dma) @@ -1523,7 +1538,8 @@ chan_prep_slave_sg(struct dma_chan *achan, struct scatterlist *_sg, packet_info = ((epib ? DESC_HAS_EPIB : 0) | pslen << DESC_PSLEN_SHIFT | psflags << DESC_PSFLAGS_SHIFT | - chan->qnum_complete << DESC_RETQ_SHIFT); + chan->qnum_complete << DESC_RETQ_SHIFT | + chan->dest_queue_manager << DESC_RETQMGR_SHIFT); /* Walk backwards through the scatterlist */ next_desc = 0; @@ -1932,6 +1948,8 @@ static int __devinit keystone_dma_probe(struct platform_device *pdev) resource_size_t size; int ret, num_chan = 0; u32 priority; + u32 config[4]; + u32 i; if (!node) { dev_err(&pdev->dev, "could not find device info\n"); @@ -2002,6 +2020,30 @@ static int __devinit keystone_dma_probe(struct platform_device *pdev) } dma->tx_priority = priority; + ret = of_property_read_u32(node, "logical-queue-managers", + &dma->logical_queue_managers); + if (ret < 0) { + dev_dbg(&pdev->dev, "unspecified number of logical " + "queue managers\n"); + dma->logical_queue_managers = 2; + } + + ret = of_property_read_u32(node, "queues-per-queue-manager", + &dma->queues_per_queue_manager); + if (ret < 0) { + dev_dbg(&pdev->dev, "unspecified number of queues per " + "queue manager\n"); + dma->queues_per_queue_manager = 4096; + } + + ret = of_property_read_u32_array(node, "qm-base-address", + config, dma->logical_queue_managers); + if (ret) + return ret; + + for (i = 0; i < dma->logical_queue_managers; i++) + dma->qm_base_address[i] = config[i]; + dma->max_rx_chan = max_rx_chan; dma->max_rx_flow = max_rx_flow; dma->max_tx_chan = min(max_tx_chan, max_tx_sched); |