diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/Kconfig | 4 | ||||
-rw-r--r-- | arch/arm/common/pl330.c | 116 | ||||
-rw-r--r-- | arch/arm/mm/proc-v7.S | 6 |
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 | ||
1247 | config ARM_ERRATA_720789 | 1247 | config 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 | ||
1283 | config ARM_ERRATA_751472 | 1283 | config 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 | ||
308 | enum pl330_dmac_state { | 299 | enum 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 | */ | ||
778 | static 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 | |||
781 | static inline u32 _state(struct pl330_thread *thrd) | 788 | static 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 */ | ||
840 | static 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 */ | ||
853 | static 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 | |||
864 | static void _stop(struct pl330_thread *thrd) | 846 | static 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 | ||
1780 | static int dmac_alloc_threads(struct pl330_dmac *pl330) | 1762 | static 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 |
372 | 1: | ||
371 | #endif | 373 | #endif |
372 | 374 | ||
373 | 3: mov r10, #0 | 375 | 3: mov r10, #0 |