aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/common/pl330.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/common/pl330.c')
-rw-r--r--arch/arm/common/pl330.c124
1 files changed, 56 insertions, 68 deletions
diff --git a/arch/arm/common/pl330.c b/arch/arm/common/pl330.c
index f407a6b35d3d..d8e44a43047c 100644
--- a/arch/arm/common/pl330.c
+++ b/arch/arm/common/pl330.c
@@ -221,17 +221,6 @@
221 */ 221 */
222#define MCODE_BUFF_PER_REQ 256 222#define MCODE_BUFF_PER_REQ 256
223 223
224/*
225 * Mark a _pl330_req as free.
226 * We do it by writing DMAEND as the first instruction
227 * because no valid request is going to have DMAEND as
228 * its first instruction to execute.
229 */
230#define MARK_FREE(req) do { \
231 _emit_END(0, (req)->mc_cpu); \
232 (req)->mc_len = 0; \
233 } while (0)
234
235/* If the _pl330_req is available to the client */ 224/* If the _pl330_req is available to the client */
236#define IS_FREE(req) (*((u8 *)((req)->mc_cpu)) == CMD_DMAEND) 225#define IS_FREE(req) (*((u8 *)((req)->mc_cpu)) == CMD_DMAEND)
237 226
@@ -301,8 +290,10 @@ struct pl330_thread {
301 struct pl330_dmac *dmac; 290 struct pl330_dmac *dmac;
302 /* Only two at a time */ 291 /* Only two at a time */
303 struct _pl330_req req[2]; 292 struct _pl330_req req[2];
304 /* Index of the last submitted request */ 293 /* Index of the last enqueued request */
305 unsigned lstenq; 294 unsigned lstenq;
295 /* Index of the last submitted request or -1 if the DMA is stopped */
296 int req_running;
306}; 297};
307 298
308enum pl330_dmac_state { 299enum pl330_dmac_state {
@@ -778,6 +769,22 @@ static inline void _execute_DBGINSN(struct pl330_thread *thrd,
778 writel(0, regs + DBGCMD); 769 writel(0, regs + DBGCMD);
779} 770}
780 771
772/*
773 * Mark a _pl330_req as free.
774 * We do it by writing DMAEND as the first instruction
775 * because no valid request is going to have DMAEND as
776 * its first instruction to execute.
777 */
778static void mark_free(struct pl330_thread *thrd, int idx)
779{
780 struct _pl330_req *req = &thrd->req[idx];
781
782 _emit_END(0, req->mc_cpu);
783 req->mc_len = 0;
784
785 thrd->req_running = -1;
786}
787
781static inline u32 _state(struct pl330_thread *thrd) 788static inline u32 _state(struct pl330_thread *thrd)
782{ 789{
783 void __iomem *regs = thrd->dmac->pinfo->base; 790 void __iomem *regs = thrd->dmac->pinfo->base;
@@ -836,31 +843,6 @@ static inline u32 _state(struct pl330_thread *thrd)
836 } 843 }
837} 844}
838 845
839/* If the request 'req' of thread 'thrd' is currently active */
840static inline bool _req_active(struct pl330_thread *thrd,
841 struct _pl330_req *req)
842{
843 void __iomem *regs = thrd->dmac->pinfo->base;
844 u32 buf = req->mc_bus, pc = readl(regs + CPC(thrd->id));
845
846 if (IS_FREE(req))
847 return false;
848
849 return (pc >= buf && pc <= buf + req->mc_len) ? true : false;
850}
851
852/* Returns 0 if the thread is inactive, ID of active req + 1 otherwise */
853static inline unsigned _thrd_active(struct pl330_thread *thrd)
854{
855 if (_req_active(thrd, &thrd->req[0]))
856 return 1; /* First req active */
857
858 if (_req_active(thrd, &thrd->req[1]))
859 return 2; /* Second req active */
860
861 return 0;
862}
863
864static void _stop(struct pl330_thread *thrd) 846static void _stop(struct pl330_thread *thrd)
865{ 847{
866 void __iomem *regs = thrd->dmac->pinfo->base; 848 void __iomem *regs = thrd->dmac->pinfo->base;
@@ -892,17 +874,22 @@ static bool _trigger(struct pl330_thread *thrd)
892 struct _arg_GO go; 874 struct _arg_GO go;
893 unsigned ns; 875 unsigned ns;
894 u8 insn[6] = {0, 0, 0, 0, 0, 0}; 876 u8 insn[6] = {0, 0, 0, 0, 0, 0};
877 int idx;
895 878
896 /* Return if already ACTIVE */ 879 /* Return if already ACTIVE */
897 if (_state(thrd) != PL330_STATE_STOPPED) 880 if (_state(thrd) != PL330_STATE_STOPPED)
898 return true; 881 return true;
899 882
900 if (!IS_FREE(&thrd->req[1 - thrd->lstenq])) 883 idx = 1 - thrd->lstenq;
901 req = &thrd->req[1 - thrd->lstenq]; 884 if (!IS_FREE(&thrd->req[idx]))
902 else if (!IS_FREE(&thrd->req[thrd->lstenq])) 885 req = &thrd->req[idx];
903 req = &thrd->req[thrd->lstenq]; 886 else {
904 else 887 idx = thrd->lstenq;
905 req = NULL; 888 if (!IS_FREE(&thrd->req[idx]))
889 req = &thrd->req[idx];
890 else
891 req = NULL;
892 }
906 893
907 /* Return if no request */ 894 /* Return if no request */
908 if (!req || !req->r) 895 if (!req || !req->r)
@@ -933,6 +920,8 @@ static bool _trigger(struct pl330_thread *thrd)
933 /* Only manager can execute GO */ 920 /* Only manager can execute GO */
934 _execute_DBGINSN(thrd, insn, true); 921 _execute_DBGINSN(thrd, insn, true);
935 922
923 thrd->req_running = idx;
924
936 return true; 925 return true;
937} 926}
938 927
@@ -1382,8 +1371,8 @@ static void pl330_dotask(unsigned long data)
1382 1371
1383 thrd->req[0].r = NULL; 1372 thrd->req[0].r = NULL;
1384 thrd->req[1].r = NULL; 1373 thrd->req[1].r = NULL;
1385 MARK_FREE(&thrd->req[0]); 1374 mark_free(thrd, 0);
1386 MARK_FREE(&thrd->req[1]); 1375 mark_free(thrd, 1);
1387 1376
1388 /* Clear the reset flag */ 1377 /* Clear the reset flag */
1389 pl330->dmac_tbd.reset_chan &= ~(1 << i); 1378 pl330->dmac_tbd.reset_chan &= ~(1 << i);
@@ -1461,14 +1450,12 @@ int pl330_update(const struct pl330_info *pi)
1461 1450
1462 thrd = &pl330->channels[id]; 1451 thrd = &pl330->channels[id];
1463 1452
1464 active = _thrd_active(thrd); 1453 active = thrd->req_running;
1465 if (!active) /* Aborted */ 1454 if (active == -1) /* Aborted */
1466 continue; 1455 continue;
1467 1456
1468 active -= 1;
1469
1470 rqdone = &thrd->req[active]; 1457 rqdone = &thrd->req[active];
1471 MARK_FREE(rqdone); 1458 mark_free(thrd, active);
1472 1459
1473 /* Get going again ASAP */ 1460 /* Get going again ASAP */
1474 _start(thrd); 1461 _start(thrd);
@@ -1480,13 +1467,19 @@ int pl330_update(const struct pl330_info *pi)
1480 1467
1481 /* Now that we are in no hurry, do the callbacks */ 1468 /* Now that we are in no hurry, do the callbacks */
1482 while (!list_empty(&pl330->req_done)) { 1469 while (!list_empty(&pl330->req_done)) {
1470 struct pl330_req *r;
1471
1483 rqdone = container_of(pl330->req_done.next, 1472 rqdone = container_of(pl330->req_done.next,
1484 struct _pl330_req, rqd); 1473 struct _pl330_req, rqd);
1485 1474
1486 list_del_init(&rqdone->rqd); 1475 list_del_init(&rqdone->rqd);
1487 1476
1477 /* Detach the req */
1478 r = rqdone->r;
1479 rqdone->r = NULL;
1480
1488 spin_unlock_irqrestore(&pl330->lock, flags); 1481 spin_unlock_irqrestore(&pl330->lock, flags);
1489 _callback(rqdone->r, PL330_ERR_NONE); 1482 _callback(r, PL330_ERR_NONE);
1490 spin_lock_irqsave(&pl330->lock, flags); 1483 spin_lock_irqsave(&pl330->lock, flags);
1491 } 1484 }
1492 1485
@@ -1509,7 +1502,7 @@ int pl330_chan_ctrl(void *ch_id, enum pl330_chan_op op)
1509 struct pl330_thread *thrd = ch_id; 1502 struct pl330_thread *thrd = ch_id;
1510 struct pl330_dmac *pl330; 1503 struct pl330_dmac *pl330;
1511 unsigned long flags; 1504 unsigned long flags;
1512 int ret = 0, active; 1505 int ret = 0, active = thrd->req_running;
1513 1506
1514 if (!thrd || thrd->free || thrd->dmac->state == DYING) 1507 if (!thrd || thrd->free || thrd->dmac->state == DYING)
1515 return -EINVAL; 1508 return -EINVAL;
@@ -1525,28 +1518,24 @@ int pl330_chan_ctrl(void *ch_id, enum pl330_chan_op op)
1525 1518
1526 thrd->req[0].r = NULL; 1519 thrd->req[0].r = NULL;
1527 thrd->req[1].r = NULL; 1520 thrd->req[1].r = NULL;
1528 MARK_FREE(&thrd->req[0]); 1521 mark_free(thrd, 0);
1529 MARK_FREE(&thrd->req[1]); 1522 mark_free(thrd, 1);
1530 break; 1523 break;
1531 1524
1532 case PL330_OP_ABORT: 1525 case PL330_OP_ABORT:
1533 active = _thrd_active(thrd);
1534
1535 /* Make sure the channel is stopped */ 1526 /* Make sure the channel is stopped */
1536 _stop(thrd); 1527 _stop(thrd);
1537 1528
1538 /* ABORT is only for the active req */ 1529 /* ABORT is only for the active req */
1539 if (!active) 1530 if (active == -1)
1540 break; 1531 break;
1541 1532
1542 active--;
1543
1544 thrd->req[active].r = NULL; 1533 thrd->req[active].r = NULL;
1545 MARK_FREE(&thrd->req[active]); 1534 mark_free(thrd, active);
1546 1535
1547 /* Start the next */ 1536 /* Start the next */
1548 case PL330_OP_START: 1537 case PL330_OP_START:
1549 if (!_thrd_active(thrd) && !_start(thrd)) 1538 if ((active == -1) && !_start(thrd))
1550 ret = -EIO; 1539 ret = -EIO;
1551 break; 1540 break;
1552 1541
@@ -1587,14 +1576,13 @@ int pl330_chan_status(void *ch_id, struct pl330_chanstatus *pstatus)
1587 else 1576 else
1588 pstatus->faulting = false; 1577 pstatus->faulting = false;
1589 1578
1590 active = _thrd_active(thrd); 1579 active = thrd->req_running;
1591 1580
1592 if (!active) { 1581 if (active == -1) {
1593 /* Indicate that the thread is not running */ 1582 /* Indicate that the thread is not running */
1594 pstatus->top_req = NULL; 1583 pstatus->top_req = NULL;
1595 pstatus->wait_req = NULL; 1584 pstatus->wait_req = NULL;
1596 } else { 1585 } else {
1597 active--;
1598 pstatus->top_req = thrd->req[active].r; 1586 pstatus->top_req = thrd->req[active].r;
1599 pstatus->wait_req = !IS_FREE(&thrd->req[1 - active]) 1587 pstatus->wait_req = !IS_FREE(&thrd->req[1 - active])
1600 ? thrd->req[1 - active].r : NULL; 1588 ? thrd->req[1 - active].r : NULL;
@@ -1659,9 +1647,9 @@ void *pl330_request_channel(const struct pl330_info *pi)
1659 thrd->free = false; 1647 thrd->free = false;
1660 thrd->lstenq = 1; 1648 thrd->lstenq = 1;
1661 thrd->req[0].r = NULL; 1649 thrd->req[0].r = NULL;
1662 MARK_FREE(&thrd->req[0]); 1650 mark_free(thrd, 0);
1663 thrd->req[1].r = NULL; 1651 thrd->req[1].r = NULL;
1664 MARK_FREE(&thrd->req[1]); 1652 mark_free(thrd, 1);
1665 break; 1653 break;
1666 } 1654 }
1667 } 1655 }
@@ -1767,14 +1755,14 @@ static inline void _reset_thread(struct pl330_thread *thrd)
1767 thrd->req[0].mc_bus = pl330->mcode_bus 1755 thrd->req[0].mc_bus = pl330->mcode_bus
1768 + (thrd->id * pi->mcbufsz); 1756 + (thrd->id * pi->mcbufsz);
1769 thrd->req[0].r = NULL; 1757 thrd->req[0].r = NULL;
1770 MARK_FREE(&thrd->req[0]); 1758 mark_free(thrd, 0);
1771 1759
1772 thrd->req[1].mc_cpu = thrd->req[0].mc_cpu 1760 thrd->req[1].mc_cpu = thrd->req[0].mc_cpu
1773 + pi->mcbufsz / 2; 1761 + pi->mcbufsz / 2;
1774 thrd->req[1].mc_bus = thrd->req[0].mc_bus 1762 thrd->req[1].mc_bus = thrd->req[0].mc_bus
1775 + pi->mcbufsz / 2; 1763 + pi->mcbufsz / 2;
1776 thrd->req[1].r = NULL; 1764 thrd->req[1].r = NULL;
1777 MARK_FREE(&thrd->req[1]); 1765 mark_free(thrd, 1);
1778} 1766}
1779 1767
1780static int dmac_alloc_threads(struct pl330_dmac *pl330) 1768static int dmac_alloc_threads(struct pl330_dmac *pl330)