373348a4738dbe431ad4807a60c115206546f3b3
[dragonfly.git] / sys / dev / atm / hfa / fore_load.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_load.c,v 1.13 1999/09/25 18:23:49 phk Exp $
27  *      @(#) $DragonFly: src/sys/dev/atm/hfa/fore_load.c,v 1.13 2007/07/11 23:46:58 dillon Exp $
28  */
29
30 /*
31  * FORE Systems 200-Series Adapter Support
32  * ---------------------------------------
33  *
34  * Loadable kernel module and device identification support
35  *
36  */
37
38 #include "fore_include.h"
39
40 /*
41  * Local functions
42  */
43 static int      fore_start (void);
44 static const char *     fore_pci_probe (pcici_t, pcidi_t);
45 static void     fore_pci_attach (pcici_t, int);
46 static void     fore_pci_shutdown (void *, int);
47 static void     fore_unattach (Fore_unit *);
48 static void     fore_reset (Fore_unit *);
49
50
51 /*
52  * Local variables
53  */
54 static int      fore_inited = 0;
55
56 /*
57  * Driver entry points
58  */
59 static  u_long  fore_pci_count = 0;
60
61 static struct pci_device fore_pci_device = {
62         FORE_DEV_NAME,
63         fore_pci_probe,
64         fore_pci_attach,
65         &fore_pci_count,
66         NULL
67 };
68
69 COMPAT_PCI_DRIVER(fore_pci, fore_pci_device);
70
71 /*
72  * Initialize driver processing
73  * 
74  * This will be called during module loading.  Not much to do here, as
75  * we must wait for our identify/attach routines to get called before
76  * we know what we're in for.
77  *
78  * Arguments:
79  *      none
80  *
81  * Returns:
82  *      0       startup was successful 
83  *      errno   startup failed - reason indicated
84  *
85  */
86 static int
87 fore_start()
88 {
89
90         /*
91          * Verify software version
92          */
93         if (atm_version != ATM_VERSION) {
94                 log(LOG_ERR, "version mismatch: fore=%d.%d kernel=%d.%d\n",
95                         ATM_VERS_MAJ(ATM_VERSION), ATM_VERS_MIN(ATM_VERSION),
96                         ATM_VERS_MAJ(atm_version), ATM_VERS_MIN(atm_version));
97                 return (EINVAL);
98         }
99
100         /*
101          * Initialize DMA mapping
102          */
103         DMA_INIT();
104
105         /*
106          * Start up watchdog timer
107          */
108         atm_timeout(&fore_timer, ATM_HZ * FORE_TIME_TICK, fore_timeout);
109
110         fore_inited = 1;
111
112         return (0);
113 }
114
115 /*
116  * Device probe routine
117  * 
118  * Determine if this driver will support the identified device.  If we claim
119  * to support the device, our attach routine will (later) be called for the
120  * device.
121  *
122  * Arguments:
123  *      config_id       device's PCI configuration ID
124  *      device_id       device's PCI Vendor/Device ID
125  *
126  * Returns:
127  *      name    device identification string
128  *      NULL    device not claimed by this driver
129  *
130  */
131 static const char *
132 fore_pci_probe(config_id, device_id)
133         pcici_t config_id;
134         pcidi_t device_id;
135 {
136
137         /*
138          * Initialize driver stuff
139          */
140         if (fore_inited == 0) {
141                 if (fore_start())
142                         return (NULL);
143         }
144
145         if ((device_id & 0xffff) != FORE_VENDOR_ID)
146                 return (NULL);
147
148         if (((device_id >> 16) & 0xffff) == FORE_PCA200E_ID)
149                 return ("FORE Systems PCA-200E ATM");
150
151         return (NULL);
152 }
153
154
155 /*
156  * Device attach routine
157  * 
158  * Attach a device we've previously claimed to support.  Walk through its
159  * register set and map, as required.  Determine what level the device will
160  * be interrupting at and then register an interrupt handler for it.  If we
161  * succeed, then reset the adapter and initialize the microcode.
162  * Last, register the interface with the kernel ATM services.
163  *
164  * Arguments:
165  *      config_id       device's PCI configuration ID
166  *      unit            device unit number
167  *
168  * Returns:
169  *      none
170  *
171  */
172 static void
173 fore_pci_attach(config_id, unit)
174         pcici_t config_id;
175         int     unit;
176 {
177         Fore_unit       *fup;
178         vm_offset_t     va;
179         vm_offset_t     pa;
180         pcidi_t         device_id;
181         long            val;
182         int             err_count = BOOT_LOOPS;
183
184         /*
185          * Just checking...
186          */
187         if (unit >= FORE_MAX_UNITS) {
188                 log(LOG_ERR, "%s%d: too many devices\n", 
189                         FORE_DEV_NAME, unit);
190                 return;
191         }
192
193         /*
194          * Make sure this isn't a duplicate unit
195          */
196         if (fore_units[unit] != NULL)
197                 return;
198
199         /*
200          * Allocate a new unit structure
201          */
202         fup = (Fore_unit *) atm_dev_alloc(sizeof(Fore_unit), sizeof(int), 0);
203         if (fup == NULL)
204                 return;
205
206         /*
207          * Start initializing it
208          */
209         fup->fu_unit = unit;
210         fup->fu_mtu = FORE_IFF_MTU;
211         fup->fu_pcitag = config_id;
212         fup->fu_vcc_pool = &fore_vcc_pool;
213         fup->fu_nif_pool = &fore_nif_pool;
214         fup->fu_ioctl = fore_atm_ioctl;
215         fup->fu_instvcc = fore_instvcc;
216         fup->fu_openvcc = fore_openvcc;
217         fup->fu_closevcc = fore_closevcc;
218         fup->fu_output = fore_output;
219         callout_init(&fup->fu_init_timer);
220
221         /*
222          * Get our device type
223          */
224         device_id = pci_conf_read ( config_id, PCI_ID_REG );
225         switch ((device_id >> 16) & 0xffff) {
226
227         case FORE_PCA200E_ID:
228                 fup->fu_config.ac_device = DEV_FORE_PCA200E;
229                 break;
230
231         default:
232                 fup->fu_config.ac_device = DEV_UNKNOWN;
233         }
234
235         /*
236          * Enable Memory Mapping / Bus Mastering 
237          */
238         val = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG);
239         val |= (PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
240         pci_conf_write(config_id, PCI_COMMAND_STATUS_REG, val);
241
242         /*
243          * Map RAM
244          */
245         val = pci_conf_read(config_id, PCI_COMMAND_STATUS_REG);
246         if ((val & PCIM_CMD_MEMEN) == 0) {
247                 log(LOG_ERR, "%s%d: memory mapping not enabled\n", 
248                         FORE_DEV_NAME, unit);
249                 goto failed;
250         }
251         if ((pci_map_mem(config_id, PCA200E_PCI_MEMBASE, &va, &pa)) == 0) {
252                 log(LOG_ERR, "%s%d: unable to map memory\n", 
253                         FORE_DEV_NAME, unit);
254                 goto failed;
255         }
256         fup->fu_ram = (Fore_mem *)va;
257         fup->fu_ramsize = PCA200E_RAM_SIZE;
258         fup->fu_mon = (Mon960 *)(fup->fu_ram + MON960_BASE);
259         fup->fu_ctlreg = (Fore_reg *)(va + PCA200E_HCR_OFFSET);
260         fup->fu_imask = (Fore_reg *)(va + PCA200E_IMASK_OFFSET);
261         fup->fu_psr = (Fore_reg *)(va + PCA200E_PSR_OFFSET);
262
263         /*
264          * Convert Endianess of Slave RAM accesses
265          */
266         val = pci_conf_read(config_id, PCA200E_PCI_MCTL);
267         val |= PCA200E_MCTL_SWAP;
268         pci_conf_write(config_id, PCA200E_PCI_MCTL, val);
269
270         /*
271          * Map interrupt in
272          */
273         if ( !pci_map_int( config_id, fore_intr, fup) ) {
274                 log(LOG_ERR, "%s%d: unable to map interrupt\n", 
275                         FORE_DEV_NAME, unit);
276                 goto failed;
277         }
278
279         /*
280          * Poke the hardware - boot the CP and prepare it for downloading
281          */
282         fore_reset(fup);
283
284         /*
285          * Wait for the monitor to perform self-test
286          */
287         while (CP_READ(fup->fu_mon->mon_bstat) != BOOT_MONREADY) {
288                 if (CP_READ(fup->fu_mon->mon_bstat) == BOOT_FAILTEST) {
289                         log(LOG_ERR, "%s%d: failed self-test\n", 
290                                 FORE_DEV_NAME, unit);
291                         goto failed;
292                 } else if ( --err_count == 0 ) {
293                         log(LOG_ERR, "%s%d: unable to boot - status=0x%lx\n", 
294                                 FORE_DEV_NAME, unit,
295                                 (u_long)CP_READ(fup->fu_mon->mon_bstat));
296                         goto failed;
297                 }
298                 DELAY ( BOOT_DELAY );
299         }
300
301         /*
302          * Setup the adapter config info - at least as much as we can
303          */
304         fup->fu_config.ac_vendor = VENDOR_FORE;
305         fup->fu_config.ac_vendapi = VENDAPI_FORE_1;
306         fup->fu_config.ac_media = MEDIA_OC3C;
307         fup->fu_pif.pif_pcr = ATM_PCR_OC3C;
308         fup->fu_config.ac_bustype = BUS_PCI;
309         fup->fu_config.ac_busslot = config_id->bus << 8 | config_id->slot;
310
311         /*
312          * Save device ram info for user-level programs
313          */
314         fup->fu_config.ac_ram = (long)fup->fu_ram;
315         fup->fu_config.ac_ramsize = fup->fu_ramsize;
316
317         /*
318          * Set device capabilities
319          */
320         fup->fu_pif.pif_maxvpi = FORE_MAX_VPI;
321         fup->fu_pif.pif_maxvci = FORE_MAX_VCI;
322
323         /*
324          * Register this interface with ATM core services
325          */
326         if ( atm_physif_register
327                         ((Cmn_unit *)fup, FORE_DEV_NAME, fore_services) != 0 )
328         {
329                 /*
330                  * Registration failed - back everything out
331                  */
332                 goto failed;
333         }
334
335         fore_units[unit] = fup;
336         fore_nunits++;
337
338         /*
339          * Add hook to our shutdown function
340          */
341         EVENTHANDLER_REGISTER(shutdown_post_sync, fore_pci_shutdown, fup,
342                               SHUTDOWN_PRI_DRIVER);
343
344         /*
345          * Initialize the CP microcode program.
346          */
347         fore_initialize(fup);
348
349         return;
350
351 failed:
352         /*
353          * Unattach the device from the system
354          */
355         fore_unattach(fup);
356
357         /*
358          * Free any Fore-specific device resources
359          */
360         fore_interface_free(fup);
361
362         atm_dev_free(fup);
363
364         return;
365 }
366
367 /*
368  * Device shutdown routine
369  * 
370  * Arguments:
371  *      howto           type of shutdown
372  *      fup             pointer to device unit structure
373  *
374  * Returns:
375  *      none
376  *
377  */
378 static void
379 fore_pci_shutdown(fup, howto)
380         void            *fup;
381         int             howto;
382 {
383
384         fore_reset((Fore_unit *) fup);
385
386         return;
387 }
388
389 /*
390  * Device unattach routine
391  * 
392  * Reset the physical device, remove any pending timeouts, 
393  * unmap any register sets, and unregister any interrupts.
394  *
395  * Arguments:
396  *      fup             pointer to device unit structure
397  *
398  * Returns:
399  *      none
400  */ 
401 static void
402 fore_unattach(fup)
403         Fore_unit       *fup;
404 {
405         /*
406          * Reset the board and return it to cold_start state.
407          * Hopefully, this will prevent use of resources as
408          * we're trying to free things up.
409          */
410         fore_reset(fup);
411
412         /*
413          * Lock out all device interrupts
414          */
415         DEVICE_LOCK((Cmn_unit *)fup);
416
417         /*
418          * Remove any pending timeout()'s
419          */
420         callout_stop(&fup->fu_init_timer);
421
422         /*
423          * Unmap the device interrupt
424          */
425         (void) pci_unmap_int(fup->fu_pcitag);
426
427         /*
428          * Unmap memory
429          */
430 #ifdef notdef
431         (void) pci_unmap_mem(fup->fu_pcitag, PCA200E_PCI_MEMBASE);
432 #endif
433
434         DEVICE_UNLOCK((Cmn_unit *)fup);
435 }
436
437
438 /*
439  * Device reset routine
440  * 
441  * Reset the physical device
442  *
443  * Arguments:
444  *      fup             pointer to device unit structure
445  *
446  * Returns:
447  *      none
448  */ 
449 static void
450 fore_reset(fup)
451         Fore_unit       *fup;
452 {
453         /*
454          * Reset the board and return it to cold_start state
455          */
456         crit_enter();
457         if (fup->fu_mon)
458                 fup->fu_mon->mon_bstat = CP_WRITE(BOOT_COLDSTART);
459
460         if (fup->fu_ctlreg) {
461
462                 switch (fup->fu_config.ac_device) {
463
464                 case DEV_FORE_PCA200E:
465                         /*
466                          * Reset i960 by setting and clearing RESET
467                          */
468                         PCA200E_HCR_INIT(*fup->fu_ctlreg, PCA200E_RESET);
469                         DELAY(10000);
470                         PCA200E_HCR_CLR(*fup->fu_ctlreg, PCA200E_RESET);
471                         break;
472
473                 default:
474                         panic("fore_reset: unknown device type");
475                         break;
476                 }
477         }
478         crit_exit();
479         return;
480 }
481
482
483 #ifndef ATM_LINKED
484 /*
485  *******************************************************************
486  *
487  * Loadable Module Support
488  *
489  *******************************************************************
490  */
491
492 #ifdef notdef
493
494 /*
495  * Driver entry points
496  */
497 static struct cdevsw fore_cdev = {
498         /* name */      noname,
499         /* maj */       -1,
500         /* flags */     0,
501         /* port */      NULL,
502         /* clone */     NULL,
503
504         /* open */      noopen,
505         /* close */     noclose,
506         /* read */      noread,
507         /* write */     nowrite,
508         /* ioctl */     noioctl,
509         /* poll */      nopoll,
510         /* mmap */      nommap,
511         /* strategy */  nostrategy,
512         /* dump */      nodump,
513         /* psize */     nopsize
514 };
515
516
517 /*
518  * Loadable device driver module description
519  */
520 MOD_DEV(fore, LM_DT_CHAR, -1, (void *)&fore_cdev);
521
522
523 /*
524  * Loadable module support "load" entry point
525  * 
526  * This is the routine called by the lkm driver whenever the
527  * modload(1) command is issued for this module.
528  *
529  * Arguments:
530  *      lkmtp   pointer to lkm drivers's structure
531  *      cmd     lkm command code
532  *
533  * Returns:
534  *      0       command was successful 
535  *      errno   command failed - reason indicated
536  *
537  */
538 static int
539 fore_load(lkmtp, cmd)
540         struct lkm_table        *lkmtp;
541         int             cmd;
542 {
543         return(fore_doload());
544 }
545
546
547 /*
548  * Loadable module support "unload" entry point
549  * 
550  * This is the routine called by the lkm driver whenever the
551  * modunload(1) command is issued for this module.
552  *
553  * Arguments:
554  *      lkmtp   pointer to lkm drivers's structure
555  *      cmd     lkm command code
556  *
557  * Returns:
558  *      0       command was successful 
559  *      errno   command failed - reason indicated
560  *
561  */
562 static int
563 fore_unload(lkmtp, cmd)
564         struct lkm_table        *lkmtp;
565         int             cmd;
566 {
567         return(fore_dounload());
568 }
569
570
571 /*
572  * Loadable module support entry point
573  * 
574  * This is the routine called by the lkm driver for all loadable module
575  * functions for this driver.  This routine name must be specified
576  * on the modload(1) command.  This routine will be called whenever the
577  * modload(1), modunload(1) or modstat(1) commands are issued for this
578  * module.
579  *
580  * Arguments:
581  *      lkmtp   pointer to lkm drivers's structure
582  *      cmd     lkm command code
583  *      ver     lkm version
584  *
585  * Returns:
586  *      0       command was successful 
587  *      errno   command failed - reason indicated
588  *
589  */
590 int
591 fore_mod(lkmtp, cmd, ver)
592         struct lkm_table        *lkmtp;
593         int             cmd;
594         int             ver;
595 {
596         DISPATCH(lkmtp, cmd, ver, fore_load, fore_unload, lkm_nullcmd);
597 }
598 #endif  /* notdef */
599
600 #endif  /* ATM_LINKED */
601