1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ |
2 | /* |
3 | * utils.h: Utilities for SPU-side of the context switch operation. |
4 | * |
5 | * (C) Copyright IBM 2005 |
6 | */ |
7 | |
8 | #ifndef _SPU_CONTEXT_UTILS_H_ |
9 | #define _SPU_CONTEXT_UTILS_H_ |
10 | |
11 | /* |
12 | * 64-bit safe EA. |
13 | */ |
14 | typedef union { |
15 | unsigned long long ull; |
16 | unsigned int ui[2]; |
17 | } addr64; |
18 | |
19 | /* |
20 | * 128-bit register template. |
21 | */ |
22 | typedef union { |
23 | unsigned int slot[4]; |
24 | vector unsigned int v; |
25 | } spu_reg128v; |
26 | |
27 | /* |
28 | * DMA list structure. |
29 | */ |
30 | struct dma_list_elem { |
31 | unsigned int size; |
32 | unsigned int ea_low; |
33 | }; |
34 | |
35 | /* |
36 | * Declare storage for 8-byte aligned DMA list. |
37 | */ |
38 | struct dma_list_elem dma_list[15] __attribute__ ((aligned(8))); |
39 | |
40 | /* |
41 | * External definition for storage |
42 | * declared in crt0. |
43 | */ |
44 | extern spu_reg128v regs_spill[NR_SPU_SPILL_REGS]; |
45 | |
46 | /* |
47 | * Compute LSCSA byte offset for a given field. |
48 | */ |
49 | static struct spu_lscsa *dummy = (struct spu_lscsa *)0; |
50 | #define LSCSA_BYTE_OFFSET(_field) \ |
51 | ((char *)(&(dummy->_field)) - (char *)(&(dummy->gprs[0].slot[0]))) |
52 | #define LSCSA_QW_OFFSET(_field) (LSCSA_BYTE_OFFSET(_field) >> 4) |
53 | |
54 | static inline void set_event_mask(void) |
55 | { |
56 | unsigned int event_mask = 0; |
57 | |
58 | /* Save, Step 4: |
59 | * Restore, Step 1: |
60 | * Set the SPU_RdEventMsk channel to zero to mask |
61 | * all events. |
62 | */ |
63 | spu_writech(SPU_WrEventMask, event_mask); |
64 | } |
65 | |
66 | static inline void set_tag_mask(void) |
67 | { |
68 | unsigned int tag_mask = 1; |
69 | |
70 | /* Save, Step 5: |
71 | * Restore, Step 2: |
72 | * Set the SPU_WrTagMsk channel to '01' to unmask |
73 | * only tag group 0. |
74 | */ |
75 | spu_writech(MFC_WrTagMask, tag_mask); |
76 | } |
77 | |
78 | static inline void build_dma_list(addr64 lscsa_ea) |
79 | { |
80 | unsigned int ea_low; |
81 | int i; |
82 | |
83 | /* Save, Step 6: |
84 | * Restore, Step 3: |
85 | * Update the effective address for the CSA in the |
86 | * pre-canned DMA-list in local storage. |
87 | */ |
88 | ea_low = lscsa_ea.ui[1]; |
89 | ea_low += LSCSA_BYTE_OFFSET(ls[16384]); |
90 | |
91 | for (i = 0; i < 15; i++, ea_low += 16384) { |
92 | dma_list[i].size = 16384; |
93 | dma_list[i].ea_low = ea_low; |
94 | } |
95 | } |
96 | |
97 | static inline void enqueue_putllc(addr64 lscsa_ea) |
98 | { |
99 | unsigned int ls = 0; |
100 | unsigned int size = 128; |
101 | unsigned int tag_id = 0; |
102 | unsigned int cmd = 0xB4; /* PUTLLC */ |
103 | |
104 | /* Save, Step 12: |
105 | * Restore, Step 7: |
106 | * Send a PUTLLC (tag 0) command to the MFC using |
107 | * an effective address in the CSA in order to |
108 | * remove any possible lock-line reservation. |
109 | */ |
110 | spu_writech(MFC_LSA, ls); |
111 | spu_writech(MFC_EAH, lscsa_ea.ui[0]); |
112 | spu_writech(MFC_EAL, lscsa_ea.ui[1]); |
113 | spu_writech(MFC_Size, size); |
114 | spu_writech(MFC_TagID, tag_id); |
115 | spu_writech(MFC_Cmd, cmd); |
116 | } |
117 | |
118 | static inline void set_tag_update(void) |
119 | { |
120 | unsigned int update_any = 1; |
121 | |
122 | /* Save, Step 15: |
123 | * Restore, Step 8: |
124 | * Write the MFC_TagUpdate channel with '01'. |
125 | */ |
126 | spu_writech(MFC_WrTagUpdate, update_any); |
127 | } |
128 | |
129 | static inline void read_tag_status(void) |
130 | { |
131 | /* Save, Step 16: |
132 | * Restore, Step 9: |
133 | * Read the MFC_TagStat channel data. |
134 | */ |
135 | spu_readch(MFC_RdTagStat); |
136 | } |
137 | |
138 | static inline void read_llar_status(void) |
139 | { |
140 | /* Save, Step 17: |
141 | * Restore, Step 10: |
142 | * Read the MFC_AtomicStat channel data. |
143 | */ |
144 | spu_readch(MFC_RdAtomicStat); |
145 | } |
146 | |
147 | #endif /* _SPU_CONTEXT_UTILS_H_ */ |
148 | |