kernel: Sync ACPICA with Intel's version 20140424.
[dragonfly.git] / sys / dev / atm / hfa / fore_command.c
1 /*
2  *
3  * ===================================
4  * HARP  |  Host ATM Research Platform
5  * ===================================
6  *
7  *
8  * This Host ATM Research Platform ("HARP") file (the "Software") is
9  * made available by Network Computing Services, Inc. ("NetworkCS")
10  * "AS IS".  NetworkCS does not provide maintenance, improvements or
11  * support of any kind.
12  *
13  * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
14  * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
15  * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
16  * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
17  * In no event shall NetworkCS be responsible for any damages, including
18  * but not limited to consequential damages, arising from or relating to
19  * any use of the Software or related support.
20  *
21  * Copyright 1994-1998 Network Computing Services, Inc.
22  *
23  * Copies of this Software may be made, however, the above copyright
24  * notice must be reproduced on all copies.
25  *
26  *      @(#) $FreeBSD: src/sys/dev/hfa/fore_command.c,v 1.6 1999/08/28 00:41:49 peter Exp $
27  *      @(#) $DragonFly: src/sys/dev/atm/hfa/fore_command.c,v 1.6 2008/03/01 22:03:13 swildner Exp $
28  */
29
30 /*
31  * FORE Systems 200-Series Adapter Support
32  * ---------------------------------------
33  *
34  * Command queue management
35  *
36  */
37
38 #include "fore_include.h"
39
40 /*
41  * Local variables
42  */
43 static struct t_atm_cause       fore_cause = {
44         T_ATM_ITU_CODING,
45         T_ATM_LOC_USER,
46         T_ATM_CAUSE_TEMPORARY_FAILURE,
47         {0, 0, 0, 0}
48 };
49
50
51 /*
52  * Allocate Command Queue Data Structures
53  *
54  * Arguments:
55  *      fup             pointer to device unit structure
56  *
57  * Returns:
58  *      0               allocations successful
59  *      else            allocation failed
60  */
61 int
62 fore_cmd_allocate(Fore_unit *fup)
63 {
64         caddr_t         memp;
65
66         /*
67          * Allocate non-cacheable memory for command status words
68          */
69         memp = atm_dev_alloc(sizeof(Q_status) * CMD_QUELEN,
70                         QSTAT_ALIGN, ATM_DEV_NONCACHE);
71         if (memp == NULL) {
72                 return (1);
73         }
74         fup->fu_cmd_stat = (Q_status *) memp;
75
76         memp = DMA_GET_ADDR(fup->fu_cmd_stat, sizeof(Q_status) * CMD_QUELEN,
77                         QSTAT_ALIGN, ATM_DEV_NONCACHE);
78         if (memp == NULL) {
79                 return (1);
80         }
81         fup->fu_cmd_statd = (Q_status *) memp;
82
83         /*
84          * Allocate memory for statistics buffer
85          */
86         memp = atm_dev_alloc(sizeof(Fore_stats), FORE_STATS_ALIGN, 0);
87         if (memp == NULL) {
88                 return (1);
89         }
90         fup->fu_stats = (Fore_stats *) memp;
91
92         /*
93          * Allocate memory for PROM buffer
94          */
95         memp = atm_dev_alloc(sizeof(Fore_prom), FORE_PROM_ALIGN, 0);
96         if (memp == NULL) {
97                 return (1);
98         }
99         fup->fu_prom = (Fore_prom *) memp;
100
101         return (0);
102 }
103
104
105 /*
106  * Command Queue Initialization
107  *
108  * Allocate and initialize the host-resident command queue structures
109  * and then initialize the CP-resident queue structures.
110  * 
111  * Called at interrupt level.
112  *
113  * Arguments:
114  *      fup             pointer to device unit structure
115  *
116  * Returns:
117  *      none
118  */
119 void
120 fore_cmd_initialize(Fore_unit *fup)
121 {
122         Aali            *aap = fup->fu_aali;
123         Cmd_queue       *cqp;
124         H_cmd_queue     *hcp;
125         Q_status        *qsp;
126         Q_status        *qsp_dma;
127         int             i;
128
129         /*
130          * Point to CP-resident command queue
131          */
132         cqp = (Cmd_queue *)(fup->fu_ram + CP_READ(aap->aali_cmd_q));
133
134         /*
135          * Point to host-resident command queue structures
136          */
137         hcp = fup->fu_cmd_q;
138         qsp = fup->fu_cmd_stat;
139         qsp_dma = fup->fu_cmd_statd;
140
141         /*
142          * Loop thru all queue entries and do whatever needs doing
143          */
144         for (i = 0; i < CMD_QUELEN; i++) {
145
146                 /*
147                  * Set queue status word to free
148                  */
149                 *qsp = QSTAT_FREE;
150
151                 /*
152                  * Set up host queue entry and link into ring
153                  */
154                 hcp->hcq_cpelem = cqp;
155                 hcp->hcq_status = qsp;
156                 if (i == (CMD_QUELEN - 1))
157                         hcp->hcq_next = fup->fu_cmd_q;
158                 else
159                         hcp->hcq_next = hcp + 1;
160
161                 /*
162                  * Now let the CP into the game
163                  */
164                 cqp->cmdq_status = (CP_dma) CP_WRITE(qsp_dma);
165
166                 /*
167                  * Bump all queue pointers
168                  */
169                 hcp++;
170                 qsp++;
171                 qsp_dma++;
172                 cqp++;
173         }
174
175         /*
176          * Initialize queue pointers
177          */
178         fup->fu_cmd_head = fup->fu_cmd_tail = fup->fu_cmd_q;
179
180         return;
181 }
182
183
184 /*
185  * Drain Command Queue
186  *
187  * This function will process and free all completed entries at the head 
188  * of the command queue. 
189  *
190  * May be called in interrupt state.  
191  * Must be called with interrupts locked out.
192  *
193  * Arguments:
194  *      fup             pointer to device unit structure
195  *
196  * Returns:
197  *      none
198  */
199 void
200 fore_cmd_drain(Fore_unit *fup)
201 {
202         H_cmd_queue     *hcp;
203         Fore_vcc        *fvp;
204
205         /*
206          * Process each completed entry
207          */
208         while (*fup->fu_cmd_head->hcq_status & QSTAT_COMPLETED) {
209
210                 hcp = fup->fu_cmd_head;
211
212                 /*
213                  * Process command completion
214                  */
215                 switch (hcp->hcq_code) {
216
217                 case CMD_ACT_VCCIN:
218                 case CMD_ACT_VCCOUT:
219                         fvp = hcp->hcq_arg;
220                         if (*hcp->hcq_status & QSTAT_ERROR) {
221                                 /*
222                                  * VCC activation failed - just abort vcc
223                                  */
224                                 if (fvp)
225                                         atm_cm_abort(fvp->fv_connvc,
226                                                 &fore_cause);
227                                 fup->fu_pif.pif_cmderrors++;
228                         } else {
229                                 /*
230                                  * Successful VCC activation
231                                  */
232                                 if (fvp) {
233                                         fvp->fv_state = CVS_ACTIVE;
234                                         fup->fu_open_vcc++;
235                                 }
236                         }
237                         break;
238
239                 case CMD_DACT_VCCIN:
240                 case CMD_DACT_VCCOUT:
241                         fvp = hcp->hcq_arg;
242                         if (*hcp->hcq_status & QSTAT_ERROR) {
243                                 /*
244                                  * VCC dactivation failed - whine
245                                  */
246                                 log(LOG_ERR, 
247                                    "fore_cmd_drain: DACT failed, vcc=(%d,%d)\n",
248                                         fvp->fv_connvc->cvc_vcc->vc_vpi,
249                                         fvp->fv_connvc->cvc_vcc->vc_vci);
250                                 fup->fu_pif.pif_cmderrors++;
251                         } else {
252                                 /*
253                                  * Successful VCC dactivation - so what?
254                                  */
255                         }
256                         break;
257
258                 case CMD_GET_STATS:
259                         if (*hcp->hcq_status & QSTAT_ERROR) {
260                                 /*
261                                  * Couldn't get stats
262                                  */
263                                 fup->fu_pif.pif_cmderrors++;
264                                 fup->fu_stats_ret = EIO;
265                         } else {
266                                 /*
267                                  * Stats are now in unit buffer
268                                  */
269                                 fup->fu_stats_ret = 0;
270                         }
271                         DMA_FREE_ADDR(fup->fu_stats, fup->fu_statsd,
272                                 sizeof(Fore_cp_stats), 0);
273                         fup->fu_flags &= ~FUF_STATCMD;
274
275                         /*
276                          * Flush received stats data
277                          */
278 #ifdef VAC
279                         if (vac)
280                                 vac_pageflush((addr_t)fup->fu_stats);
281 #endif
282
283 #if BYTE_ORDER == LITTLE_ENDIAN
284                         /*
285                          * Little endian machines receives the stats in
286                          * wrong byte order. Instead of swapping in user
287                          * land, swap here so that everything going out
288                          * of the kernel is in correct host order.
289                          */
290                         {
291                                 u_long *bp = (u_long *)fup->fu_stats;
292                                 int     loop;
293
294                                 for ( loop = 0; loop < sizeof(Fore_cp_stats)/
295                                     sizeof(long); loop++, bp++ )
296                                         *bp = ntohl(*bp);
297                         }
298 #endif  /* BYTE_ORDER == LITTLE_ENDIAN */
299
300                         /*
301                          * Poke whoever is waiting on the stats
302                          */
303                         wakeup((caddr_t)&fup->fu_stats);
304                         break;
305
306                 case CMD_GET_PROM:
307                         if (*hcp->hcq_status & QSTAT_ERROR) {
308                                 /*
309                                  * Couldn't get PROM data
310                                  */
311                                 fup->fu_pif.pif_cmderrors++;
312                                 log(LOG_ERR, 
313                                     "fore_cmd_drain: %s%d: GET_PROM failed\n",
314                                         fup->fu_pif.pif_name,
315                                         fup->fu_pif.pif_unit);
316                         } else {
317                                 Fore_prom       *fp = fup->fu_prom;
318
319                                 /*
320                                  * Flush received PROM data
321                                  */
322 #ifdef VAC
323                                 if (vac)
324                                         vac_pageflush((addr_t)fp);
325 #endif
326                                 /*
327                                  * Copy PROM info into config areas
328                                  */
329                                 KM_COPY(&fp->pr_mac[2],
330                                         &fup->fu_pif.pif_macaddr,
331                                         sizeof(struct mac_addr));
332                                 fup->fu_config.ac_macaddr = 
333                                         fup->fu_pif.pif_macaddr;
334                                 ksnprintf(fup->fu_config.ac_hard_vers,
335                                     sizeof(fup->fu_config.ac_hard_vers),
336                                         "%ld.%ld.%ld",
337                                         (fp->pr_hwver >> 16) & 0xff,
338                                         (fp->pr_hwver >> 8) & 0xff,
339                                         fp->pr_hwver & 0xff);
340                                 fup->fu_config.ac_serial = fp->pr_serno;
341                         }
342
343                         DMA_FREE_ADDR(fup->fu_prom, fup->fu_promd,
344                                 sizeof(Fore_prom), 0);
345                         break;
346
347                 default:
348                         log(LOG_ERR, "fore_cmd_drain: unknown command %ld\n",
349                                 hcp->hcq_code);
350                 }
351
352                 /*
353                  * Mark this entry free for use and bump head pointer
354                  * to the next entry in the queue
355                  */
356                 *hcp->hcq_status = QSTAT_FREE;
357                 fup->fu_cmd_head = hcp->hcq_next;
358         }
359
360         return;
361 }
362
363
364 /*
365  * Free Command Queue Data Structures
366  *
367  * Arguments:
368  *      fup             pointer to device unit structure
369  *
370  * Returns:
371  *      none
372  */
373 void
374 fore_cmd_free(Fore_unit *fup)
375 {
376         H_cmd_queue     *hcp;
377
378         /*
379          * Deal with any commands left on the queue
380          */
381         if (fup->fu_flags & CUF_INITED) {
382                 while (*fup->fu_cmd_head->hcq_status != QSTAT_FREE) {
383                         hcp = fup->fu_cmd_head;
384
385                         switch (hcp->hcq_code) {
386
387                         case CMD_GET_STATS:
388                                 /*
389                                  * Just in case someone is sleeping on this
390                                  */
391                                 fup->fu_stats_ret = EIO;
392                                 wakeup((caddr_t)&fup->fu_stats);
393                                 break;
394                         }
395
396                         *hcp->hcq_status = QSTAT_FREE;
397                         fup->fu_cmd_head = hcp->hcq_next;
398                 }
399         }
400
401         /*
402          * Free the statistics buffer
403          */
404         if (fup->fu_stats) {
405                 atm_dev_free(fup->fu_stats);
406                 fup->fu_stats = NULL;
407         }
408
409         /*
410          * Free the PROM buffer
411          */
412         if (fup->fu_prom) {
413                 atm_dev_free(fup->fu_prom);
414                 fup->fu_prom = NULL;
415         }
416
417         /*
418          * Free the status words
419          */
420         if (fup->fu_cmd_stat) {
421                 if (fup->fu_cmd_statd) {
422                         DMA_FREE_ADDR(fup->fu_cmd_stat, fup->fu_cmd_statd,
423                                 sizeof(Q_status) * CMD_QUELEN,
424                                 ATM_DEV_NONCACHE);
425                 }
426                 atm_dev_free((volatile void *)fup->fu_cmd_stat);
427                 fup->fu_cmd_stat = NULL;
428                 fup->fu_cmd_statd = NULL;
429         }
430
431         return;
432 }
433