aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/Kconfig4
-rw-r--r--arch/arm/common/pl330.c116
-rw-r--r--arch/arm/mm/proc-v7.S6
3 files changed, 55 insertions, 71 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 776d76b8cb69..b259c7c644e3 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1246,7 +1246,7 @@ config PL310_ERRATA_588369
1246 1246
1247config ARM_ERRATA_720789 1247config ARM_ERRATA_720789
1248 bool "ARM errata: TLBIASIDIS and TLBIMVAIS operations can broadcast a faulty ASID" 1248 bool "ARM errata: TLBIASIDIS and TLBIMVAIS operations can broadcast a faulty ASID"
1249 depends on CPU_V7 && SMP 1249 depends on CPU_V7
1250 help 1250 help
1251 This option enables the workaround for the 720789 Cortex-A9 (prior to 1251 This option enables the workaround for the 720789 Cortex-A9 (prior to
1252 r2p0) erratum. A faulty ASID can be sent to the other CPUs for the 1252 r2p0) erratum. A faulty ASID can be sent to the other CPUs for the
@@ -1282,7 +1282,7 @@ config ARM_ERRATA_743622
1282 1282
1283config ARM_ERRATA_751472 1283config ARM_ERRATA_751472
1284 bool "ARM errata: Interrupted ICIALLUIS may prevent completion of broadcasted operation" 1284 bool "ARM errata: Interrupted ICIALLUIS may prevent completion of broadcasted operation"
1285 depends on CPU_V7 && SMP 1285 depends on CPU_V7
1286 help 1286 help
1287 This option enables the workaround for the 751472 Cortex-A9 (prior 1287 This option enables the workaround for the 751472 Cortex-A9 (prior
1288 to r3p0) erratum. An interrupted ICIALLUIS operation may prevent the 1288 to r3p0) erratum. An interrupted ICIALLUIS operation may prevent the
diff --git a/arch/arm/common/pl330.c b/arch/arm/common/pl330.c
index f407a6b35d3d..8d8df744f7a5 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);
@@ -1509,7 +1496,7 @@ int pl330_chan_ctrl(void *ch_id, enum pl330_chan_op op)
1509 struct pl330_thread *thrd = ch_id; 1496 struct pl330_thread *thrd = ch_id;
1510 struct pl330_dmac *pl330; 1497 struct pl330_dmac *pl330;
1511 unsigned long flags; 1498 unsigned long flags;
1512 int ret = 0, active; 1499 int ret = 0, active = thrd->req_running;
1513 1500
1514 if (!thrd || thrd->free || thrd->dmac->state == DYING) 1501 if (!thrd || thrd->free || thrd->dmac->state == DYING)
1515 return -EINVAL; 1502 return -EINVAL;
@@ -1525,28 +1512,24 @@ int pl330_chan_ctrl(void *ch_id, enum pl330_chan_op op)
1525 1512
1526 thrd->req[0].r = NULL; 1513 thrd->req[0].r = NULL;
1527 thrd->req[1].r = NULL; 1514 thrd->req[1].r = NULL;
1528 MARK_FREE(&thrd->req[0]); 1515 mark_free(thrd, 0);
1529 MARK_FREE(&thrd->req[1]); 1516 mark_free(thrd, 1);
1530 break; 1517 break;
1531 1518
1532 case PL330_OP_ABORT: 1519 case PL330_OP_ABORT:
1533 active = _thrd_active(thrd);
1534
1535 /* Make sure the channel is stopped */ 1520 /* Make sure the channel is stopped */
1536 _stop(thrd); 1521 _stop(thrd);
1537 1522
1538 /* ABORT is only for the active req */ 1523 /* ABORT is only for the active req */
1539 if (!active) 1524 if (active == -1)
1540 break; 1525 break;
1541 1526
1542 active--;
1543
1544 thrd->req[active].r = NULL; 1527 thrd->req[active].r = NULL;
1545 MARK_FREE(&thrd->req[active]); 1528 mark_free(thrd, active);
1546 1529
1547 /* Start the next */ 1530 /* Start the next */
1548 case PL330_OP_START: 1531 case PL330_OP_START:
1549 if (!_thrd_active(thrd) && !_start(thrd)) 1532 if ((active == -1) && !_start(thrd))
1550 ret = -EIO; 1533 ret = -EIO;
1551 break; 1534 break;
1552 1535
@@ -1587,14 +1570,13 @@ int pl330_chan_status(void *ch_id, struct pl330_chanstatus *pstatus)
1587 else 1570 else
1588 pstatus->faulting = false; 1571 pstatus->faulting = false;
1589 1572
1590 active = _thrd_active(thrd); 1573 active = thrd->req_running;
1591 1574
1592 if (!active) { 1575 if (active == -1) {
1593 /* Indicate that the thread is not running */ 1576 /* Indicate that the thread is not running */
1594 pstatus->top_req = NULL; 1577 pstatus->top_req = NULL;
1595 pstatus->wait_req = NULL; 1578 pstatus->wait_req = NULL;
1596 } else { 1579 } else {
1597 active--;
1598 pstatus->top_req = thrd->req[active].r; 1580 pstatus->top_req = thrd->req[active].r;
1599 pstatus->wait_req = !IS_FREE(&thrd->req[1 - active]) 1581 pstatus->wait_req = !IS_FREE(&thrd->req[1 - active])
1600 ? thrd->req[1 - active].r : NULL; 1582 ? thrd->req[1 - active].r : NULL;
@@ -1659,9 +1641,9 @@ void *pl330_request_channel(const struct pl330_info *pi)
1659 thrd->free = false; 1641 thrd->free = false;
1660 thrd->lstenq = 1; 1642 thrd->lstenq = 1;
1661 thrd->req[0].r = NULL; 1643 thrd->req[0].r = NULL;
1662 MARK_FREE(&thrd->req[0]); 1644 mark_free(thrd, 0);
1663 thrd->req[1].r = NULL; 1645 thrd->req[1].r = NULL;
1664 MARK_FREE(&thrd->req[1]); 1646 mark_free(thrd, 1);
1665 break; 1647 break;
1666 } 1648 }
1667 } 1649 }
@@ -1767,14 +1749,14 @@ static inline void _reset_thread(struct pl330_thread *thrd)
1767 thrd->req[0].mc_bus = pl330->mcode_bus 1749 thrd->req[0].mc_bus = pl330->mcode_bus
1768 + (thrd->id * pi->mcbufsz); 1750 + (thrd->id * pi->mcbufsz);
1769 thrd->req[0].r = NULL; 1751 thrd->req[0].r = NULL;
1770 MARK_FREE(&thrd->req[0]); 1752 mark_free(thrd, 0);
1771 1753
1772 thrd->req[1].mc_cpu = thrd->req[0].mc_cpu 1754 thrd->req[1].mc_cpu = thrd->req[0].mc_cpu
1773 + pi->mcbufsz / 2; 1755 + pi->mcbufsz / 2;
1774 thrd->req[1].mc_bus = thrd->req[0].mc_bus 1756 thrd->req[1].mc_bus = thrd->req[0].mc_bus
1775 + pi->mcbufsz / 2; 1757 + pi->mcbufsz / 2;
1776 thrd->req[1].r = NULL; 1758 thrd->req[1].r = NULL;
1777 MARK_FREE(&thrd->req[1]); 1759 mark_free(thrd, 1);
1778} 1760}
1779 1761
1780static int dmac_alloc_threads(struct pl330_dmac *pl330) 1762static int dmac_alloc_threads(struct pl330_dmac *pl330)
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index 2c559ac38142..e70a73731eaa 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -363,11 +363,13 @@ __v7_setup:
363 orreq r10, r10, #1 << 6 @ set bit #6 363 orreq r10, r10, #1 << 6 @ set bit #6
364 mcreq p15, 0, r10, c15, c0, 1 @ write diagnostic register 364 mcreq p15, 0, r10, c15, c0, 1 @ write diagnostic register
365#endif 365#endif
366#ifdef CONFIG_ARM_ERRATA_751472 366#if defined(CONFIG_ARM_ERRATA_751472) && defined(CONFIG_SMP)
367 cmp r6, #0x30 @ present prior to r3p0 367 ALT_SMP(cmp r6, #0x30) @ present prior to r3p0
368 ALT_UP_B(1f)
368 mrclt p15, 0, r10, c15, c0, 1 @ read diagnostic register 369 mrclt p15, 0, r10, c15, c0, 1 @ read diagnostic register
369 orrlt r10, r10, #1 << 11 @ set bit #11 370 orrlt r10, r10, #1 << 11 @ set bit #11
370 mcrlt p15, 0, r10, c15, c0, 1 @ write diagnostic register 371 mcrlt p15, 0, r10, c15, c0, 1 @ write diagnostic register
3721:
371#endif 373#endif
372 374
3733: mov r10, #0 3753: mov r10, #0