Centralize if queue handling.
[dragonfly.git] / sys / dev / atm / hfa / fore_init.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_init.c,v 1.6 1999/08/29 10:28:09 bde Exp $
27  *      @(#) $DragonFly: src/sys/dev/atm/hfa/fore_init.c,v 1.4 2003/08/27 10:35:16 rob Exp $
28  */
29
30 /*
31  * FORE Systems 200-Series Adapter Support
32  * ---------------------------------------
33  *
34  * Cell Processor (CP) initialization routines
35  *
36  */
37
38 #include "fore_include.h"
39
40 /*
41  * Local functions
42  */
43 #ifdef FORE_PCI
44 static void     fore_get_prom (Fore_unit *);
45 #endif
46
47
48 /*
49  * Begin CP Initialization
50  *
51  * This function will poll for the successful downloading and starting of
52  * the CP microcode program.  After the microcode is running, we will allocate
53  * any needed kernel memory (must do it in non-interrupt mode), build the CP
54  * queue configurations and issue an Initialize command to the CP.
55  *
56  * Arguments:
57  *      fup             pointer to device unit structure
58  *
59  * Returns:
60  *      none
61  */
62 void
63 fore_initialize(fup)
64         Fore_unit       *fup;
65 {
66         Aali            *aap;
67         Init_parms      *inp;
68         caddr_t         errmsg;
69         u_long          vers;
70
71         /*
72          * Must wait until firmware has been downloaded and is running
73          */
74         if (CP_READ(fup->fu_mon->mon_bstat) != BOOT_RUNNING) {
75
76                 /*
77                  * Try again later
78                  */
79                 fup->fu_thandle = 
80                         timeout((KTimeout_ret(*) (void *))fore_initialize,
81                                 (void *)fup, hz);
82                 return;
83         } else
84                 callout_handle_init(&fup->fu_thandle);
85
86         /*
87          * Allocate queues and whatever else is needed
88          */
89         if (fore_xmit_allocate(fup)) {
90                 errmsg = "transmit queue allocation";
91                 goto failed;
92         }
93         if (fore_recv_allocate(fup)) {
94                 errmsg = "receive queue allocation";
95                 goto failed;
96         }
97         if (fore_buf_allocate(fup)) {
98                 errmsg = "buffer supply queue allocation";
99                 goto failed;
100         }
101         if (fore_cmd_allocate(fup)) {
102                 errmsg = "command queue allocation";
103                 goto failed;
104         }
105
106         /*
107          * CP microcode is downloaded - locate shared memory interface 
108          */
109         aap = (Aali *)(fup->fu_ram + CP_READ(fup->fu_mon->mon_appl));
110         fup->fu_aali = aap;
111
112         /*
113          * Pick out any interesting info from the microcode
114          */
115         vers = CP_READ(aap->aali_ucode_ver);
116         if (vers < FORE_MIN_UCODE) {
117                 errmsg = "unsupported microcode version";
118                 goto failed;
119         }
120         snprintf(fup->fu_config.ac_firm_vers,
121             sizeof(fup->fu_config.ac_firm_vers), "%ld.%ld.%ld",
122                 (vers >> 16) & 0xff, (vers >> 8) & 0xff, vers & 0xff);
123
124 #ifdef notdef
125         /*
126          * Turn on CP debugging
127          */
128         aap->aali_hostlog = 1;
129 #endif
130
131         /*
132          * Build the initialization block
133          */
134         inp = &aap->aali_init;
135         inp->init_numvcc = CP_WRITE(FORE_MAX_VCC);
136         inp->init_cmd_elem = CP_WRITE(CMD_QUELEN);
137         inp->init_xmit_elem = CP_WRITE(XMIT_QUELEN);
138         inp->init_recv_elem = CP_WRITE(RECV_QUELEN);
139         inp->init_recv_ext = CP_WRITE(RECV_EXTRA_SEGS);
140         inp->init_xmit_ext = CP_WRITE(XMIT_EXTRA_SEGS);
141         inp->init_buf1s.bfs_quelen = CP_WRITE(BUF1_SM_QUELEN);
142         inp->init_buf1s.bfs_bufsize = CP_WRITE(BUF1_SM_SIZE);
143         inp->init_buf1s.bfs_cppool = CP_WRITE(BUF1_SM_CPPOOL);
144         inp->init_buf1s.bfs_entsize = CP_WRITE(BUF1_SM_ENTSIZE);
145         inp->init_buf1l.bfs_quelen = CP_WRITE(BUF1_LG_QUELEN);
146         inp->init_buf1l.bfs_bufsize = CP_WRITE(BUF1_LG_SIZE);
147         inp->init_buf1l.bfs_cppool = CP_WRITE(BUF1_LG_CPPOOL);
148         inp->init_buf1l.bfs_entsize = CP_WRITE(BUF1_LG_ENTSIZE);
149         inp->init_buf2s.bfs_quelen = CP_WRITE(0);
150         inp->init_buf2s.bfs_bufsize = CP_WRITE(0);
151         inp->init_buf2s.bfs_cppool = CP_WRITE(0);
152         inp->init_buf2s.bfs_entsize = CP_WRITE(0);
153         inp->init_buf2l.bfs_quelen = CP_WRITE(0);
154         inp->init_buf2l.bfs_bufsize = CP_WRITE(0);
155         inp->init_buf2l.bfs_cppool = CP_WRITE(0);
156         inp->init_buf2l.bfs_entsize = CP_WRITE(0);
157
158         /*
159          * Enable device interrupts
160          */
161         aap->aali_intr_ena = CP_WRITE(1);
162
163         /*
164          * Issue the Initialize command to the CP and wait for
165          * the CP to interrupt to signal completion
166          */
167         inp->init_status = CP_WRITE(QSTAT_PENDING);
168         inp->init_cmd = CP_WRITE(CMD_INIT | CMD_INTR_REQ);
169         return;
170
171 failed:
172         /*
173          * Initialization failure
174          */
175         fore_interface_free(fup);
176         log(LOG_ERR, "fore initialization failed: intf=%s%d, err=%s\n",
177                 fup->fu_pif.pif_name, fup->fu_pif.pif_unit, errmsg);
178         return;
179 }
180
181
182 /*
183  * Complete CP Initialization 
184  *
185  * Called after the CP has successfully completed processing of the 
186  * Initialize command.  We will now finish off our part of the 
187  * initialization process by setting up all the host-based queue 
188  * management structures.
189  *
190  * Called at interrupt level.
191  *
192  * Arguments:
193  *      fup             pointer to device unit structure
194  *
195  * Returns:
196  *      none
197  */
198 void
199 fore_initialize_complete(fup)
200         Fore_unit       *fup;
201 {
202         Aali            *aap = fup->fu_aali;
203
204         /*
205          * Log an initialization failure
206          */
207         if (CP_READ(aap->aali_init.init_status) & QSTAT_ERROR) {
208
209                 log(LOG_ERR, 
210                         "fore initialization failed: intf=%s%d, hbeat=0x%lx\n",
211                         fup->fu_pif.pif_name, fup->fu_pif.pif_unit,
212                         (u_long)CP_READ(aap->aali_heartbeat));
213                 return;
214         }
215
216         ATM_DEBUG1("heap=0x%lx\n", aap->aali_heap);
217         ATM_DEBUG1("heaplen=0x%lx\n", aap->aali_heaplen);
218         ATM_DEBUG1("cmd_q=0x%lx\n", aap->aali_cmd_q);
219         ATM_DEBUG1("xmit_q=0x%lx\n", aap->aali_xmit_q);
220         ATM_DEBUG1("recv_q=0x%lx\n", aap->aali_recv_q);
221         ATM_DEBUG1("buf1s_q=0x%lx\n", aap->aali_buf1s_q);
222         ATM_DEBUG1("buf1l_q=0x%lx\n", aap->aali_buf1l_q);
223         ATM_DEBUG1("buf2s_q=0x%lx\n", aap->aali_buf2s_q);
224         ATM_DEBUG1("buf2l_q=0x%lx\n", aap->aali_buf2l_q);
225
226         /*
227          * Initialize all of our queues
228          */
229         fore_xmit_initialize(fup);
230         fore_recv_initialize(fup);
231         fore_buf_initialize(fup);
232         fore_cmd_initialize(fup);
233
234         /*
235          * Mark device initialization completed
236          */
237         fup->fu_flags |= CUF_INITED;
238
239 #ifdef FORE_PCI
240         fore_get_prom(fup);
241 #endif
242         return;
243 }
244
245
246 #ifdef FORE_PCI
247 /*
248  * Get device PROM values from CP
249  * 
250  * This function will issue a GET_PROM command to the CP in order to
251  * initiate the DMA transfer of the CP's PROM structure to the host.
252  * This will be called after CP initialization has completed.
253  * There is (currently) no retry if this fails.
254  *
255  * Called at interrupt level.
256  *
257  * Arguments:
258  *      fup     pointer to device unit structure
259  *
260  * Returns:
261  *      none
262  *
263  */
264 static void
265 fore_get_prom(fup)
266         Fore_unit       *fup;
267 {
268         H_cmd_queue     *hcp;
269         Cmd_queue       *cqp;
270
271         /*
272          * Queue command at end of command queue
273          */
274         hcp = fup->fu_cmd_tail;
275         if ((*hcp->hcq_status) & QSTAT_FREE) {
276
277                 /*
278                  * Queue entry available, so set our view of things up
279                  */
280                 hcp->hcq_code = CMD_GET_PROM;
281                 hcp->hcq_arg = NULL;
282                 fup->fu_cmd_tail = hcp->hcq_next;
283
284                 /*
285                  * Now set the CP-resident queue entry - the CP will grab
286                  * the command when the op-code is set.
287                  */
288                 cqp = hcp->hcq_cpelem;
289                 (*hcp->hcq_status) = QSTAT_PENDING;
290
291                 fup->fu_promd = DMA_GET_ADDR(fup->fu_prom, sizeof(Fore_prom),
292                         FORE_PROM_ALIGN, 0);
293                 if (fup->fu_promd == NULL) {
294                         fup->fu_stats->st_drv.drv_cm_nodma++;
295                         return;
296                 }
297                 cqp->cmdq_prom.prom_buffer = (CP_dma) CP_WRITE(fup->fu_promd);
298                 cqp->cmdq_prom.prom_cmd = CP_WRITE(CMD_GET_PROM | CMD_INTR_REQ);
299
300         } else {
301                 /*
302                  * Command queue full
303                  */
304                 fup->fu_stats->st_drv.drv_cm_full++;
305         }
306
307         return;
308 }
309 #endif  /* FORE_PCI */
310