1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#include <linux/module.h>
20#include <linux/types.h>
21#include <linux/delay.h>
22#include <linux/ktime.h>
23
24#include <linux/uaccess.h>
25#include <asm/io.h>
26
27#include "prismcompat.h"
28#include "isl_38xx.h"
29#include "islpci_dev.h"
30#include "islpci_mgt.h"
31
32
33
34
35
36
37
38
39
40
41
42
43
44void
45isl38xx_disable_interrupts(void __iomem *device)
46{
47 isl38xx_w32_flush(device, 0x00000000, ISL38XX_INT_EN_REG);
48 udelay(ISL38XX_WRITEIO_DELAY);
49}
50
51void
52isl38xx_handle_sleep_request(isl38xx_control_block *control_block,
53 int *powerstate, void __iomem *device_base)
54{
55
56
57 if (isl38xx_in_queue(control_block, ISL38XX_CB_TX_DATA_LQ))
58
59 return;
60
61 if (isl38xx_in_queue(control_block, ISL38XX_CB_TX_MGMTQ))
62
63 return;
64
65
66 if (isl38xx_in_queue(control_block, ISL38XX_CB_RX_DATA_LQ))
67
68 return;
69
70 if (isl38xx_in_queue(control_block, ISL38XX_CB_RX_MGMTQ))
71
72 return;
73
74#if VERBOSE > SHOW_ERROR_MESSAGES
75 DEBUG(SHOW_TRACING, "Device going to sleep mode\n");
76#endif
77
78
79 *powerstate = ISL38XX_PSM_POWERSAVE_STATE;
80
81
82 isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_SLEEP,
83 ISL38XX_DEV_INT_REG);
84 udelay(ISL38XX_WRITEIO_DELAY);
85}
86
87void
88isl38xx_handle_wakeup(isl38xx_control_block *control_block,
89 int *powerstate, void __iomem *device_base)
90{
91
92 *powerstate = ISL38XX_PSM_ACTIVE_STATE;
93
94
95 if (!isl38xx_in_queue(control_block, ISL38XX_CB_TX_DATA_LQ)
96 && !isl38xx_in_queue(control_block, ISL38XX_CB_TX_MGMTQ))
97 return;
98
99#if VERBOSE > SHOW_ERROR_MESSAGES
100 DEBUG(SHOW_ANYTHING, "Wake up handler trigger the device\n");
101#endif
102
103
104
105 isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_UPDATE,
106 ISL38XX_DEV_INT_REG);
107 udelay(ISL38XX_WRITEIO_DELAY);
108}
109
110void
111isl38xx_trigger_device(int asleep, void __iomem *device_base)
112{
113 u32 reg;
114
115#if VERBOSE > SHOW_ERROR_MESSAGES
116 u32 counter = 0;
117 struct timespec64 current_ts64;
118 DEBUG(SHOW_FUNCTION_CALLS, "isl38xx trigger device\n");
119#endif
120
121
122 if (asleep) {
123
124#if VERBOSE > SHOW_ERROR_MESSAGES
125 ktime_get_real_ts64(¤t_ts64);
126 DEBUG(SHOW_TRACING, "%lld.%09ld Device wakeup triggered\n",
127 (s64)current_ts64.tv_sec, current_ts64.tv_nsec);
128
129 DEBUG(SHOW_TRACING, "%lld.%09ld Device register read %08x\n",
130 (s64)current_ts64.tv_sec, current_ts64.tv_nsec,
131 readl(device_base + ISL38XX_CTRL_STAT_REG));
132#endif
133
134 reg = readl(device_base + ISL38XX_INT_IDENT_REG);
135 if (reg == 0xabadface) {
136#if VERBOSE > SHOW_ERROR_MESSAGES
137 ktime_get_real_ts64(¤t_ts64);
138 DEBUG(SHOW_TRACING,
139 "%lld.%09ld Device register abadface\n",
140 (s64)current_ts64.tv_sec, current_ts64.tv_nsec);
141#endif
142
143 while (reg = readl(device_base + ISL38XX_CTRL_STAT_REG),
144 (reg & ISL38XX_CTRL_STAT_SLEEPMODE) == 0) {
145 udelay(ISL38XX_WRITEIO_DELAY);
146#if VERBOSE > SHOW_ERROR_MESSAGES
147 counter++;
148#endif
149 }
150
151#if VERBOSE > SHOW_ERROR_MESSAGES
152 DEBUG(SHOW_TRACING,
153 "%lld.%09ld Device register read %08x\n",
154 (s64)current_ts64.tv_sec, current_ts64.tv_nsec,
155 readl(device_base + ISL38XX_CTRL_STAT_REG));
156 ktime_get_real_ts64(¤t_ts64);
157 DEBUG(SHOW_TRACING,
158 "%lld.%09ld Device asleep counter %i\n",
159 (s64)current_ts64.tv_sec, current_ts64.tv_nsec,
160 counter);
161#endif
162 }
163
164 isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_WAKEUP,
165 ISL38XX_DEV_INT_REG);
166
167#if VERBOSE > SHOW_ERROR_MESSAGES
168 udelay(ISL38XX_WRITEIO_DELAY);
169
170
171 reg = readl(device_base + ISL38XX_CTRL_STAT_REG);
172 ktime_get_real_ts64(¤t_ts64);
173 DEBUG(SHOW_TRACING, "%lld.%00ld Device register read %08x\n",
174 (s64)current_ts64.tv_sec, current_ts64.tv_nsec, reg);
175#endif
176 } else {
177
178#if VERBOSE > SHOW_ERROR_MESSAGES
179 DEBUG(SHOW_TRACING, "Device is in active state\n");
180#endif
181
182
183 isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_UPDATE,
184 ISL38XX_DEV_INT_REG);
185 }
186}
187
188void
189isl38xx_interface_reset(void __iomem *device_base, dma_addr_t host_address)
190{
191#if VERBOSE > SHOW_ERROR_MESSAGES
192 DEBUG(SHOW_FUNCTION_CALLS, "isl38xx_interface_reset\n");
193#endif
194
195
196 isl38xx_w32_flush(device_base, host_address, ISL38XX_CTRL_BLK_BASE_REG);
197 udelay(ISL38XX_WRITEIO_DELAY);
198
199
200 isl38xx_w32_flush(device_base, ISL38XX_DEV_INT_RESET, ISL38XX_DEV_INT_REG);
201 udelay(ISL38XX_WRITEIO_DELAY);
202
203
204
205
206
207
208 isl38xx_w32_flush(device_base, ISL38XX_INT_IDENT_INIT, ISL38XX_INT_EN_REG);
209 udelay(ISL38XX_WRITEIO_DELAY);
210}
211
212void
213isl38xx_enable_common_interrupts(void __iomem *device_base)
214{
215 u32 reg;
216
217 reg = ISL38XX_INT_IDENT_UPDATE | ISL38XX_INT_IDENT_SLEEP |
218 ISL38XX_INT_IDENT_WAKEUP;
219 isl38xx_w32_flush(device_base, reg, ISL38XX_INT_EN_REG);
220 udelay(ISL38XX_WRITEIO_DELAY);
221}
222
223int
224isl38xx_in_queue(isl38xx_control_block *cb, int queue)
225{
226 const s32 delta = (le32_to_cpu(cb->driver_curr_frag[queue]) -
227 le32_to_cpu(cb->device_curr_frag[queue]));
228
229
230
231
232 BUG_ON(delta < 0);
233
234 switch (queue) {
235
236 case ISL38XX_CB_TX_MGMTQ:
237 BUG_ON(delta > ISL38XX_CB_MGMT_QSIZE);
238
239 case ISL38XX_CB_TX_DATA_LQ:
240 case ISL38XX_CB_TX_DATA_HQ:
241 BUG_ON(delta > ISL38XX_CB_TX_QSIZE);
242 return delta;
243
244
245 case ISL38XX_CB_RX_MGMTQ:
246 BUG_ON(delta > ISL38XX_CB_MGMT_QSIZE);
247 return ISL38XX_CB_MGMT_QSIZE - delta;
248
249 case ISL38XX_CB_RX_DATA_LQ:
250 case ISL38XX_CB_RX_DATA_HQ:
251 BUG_ON(delta > ISL38XX_CB_RX_QSIZE);
252 return ISL38XX_CB_RX_QSIZE - delta;
253 }
254 BUG();
255 return 0;
256}
257