• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/drivers/staging/cxt1e1/
1/* Copyright (C) 2007  One Stop Systems
2 * Copyright (C) 2003-2005  SBE, Inc.
3 *
4 *   This program is free software; you can redistribute it and/or modify
5 *   it under the terms of the GNU General Public License as published by
6 *   the Free Software Foundation; either version 2 of the License, or
7 *   (at your option) any later version.
8 *
9 *   This program is distributed in the hope that it will be useful,
10 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
11 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 *   GNU General Public License for more details.
13 */
14
15#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
16
17#include <linux/netdevice.h>
18#include <linux/hdlc.h>
19#include <linux/if_arp.h>
20#include <asm/uaccess.h>
21#include <linux/rtnetlink.h>
22#include <linux/pci.h>
23#include "pmcc4_sysdep.h"
24#include "sbecom_inline_linux.h"
25#include "libsbew.h"
26#include "pmcc4_private.h"
27#include "pmcc4.h"
28#include "pmcc4_ioctls.h"
29#include "pmc93x6_eeprom.h"
30#ifdef CONFIG_PROC_FS
31#include "sbeproc.h"
32#endif
33
34#ifdef SBE_INCLUDE_SYMBOLS
35#define STATIC
36#else
37#define STATIC  static
38#endif
39
40extern int  log_level;
41extern int  error_flag;
42extern int  drvr_state;
43
44/* forward references */
45void        c4_stopwd (ci_t *);
46struct net_device * __init c4_add_dev (hdw_info_t *, int, unsigned long, unsigned long, int, int);
47
48
49struct s_hdw_info hdw_info[MAX_BOARDS];
50
51
52void        __init
53show_two (hdw_info_t * hi, int brdno)
54{
55    ci_t       *ci;
56    struct pci_dev *pdev;
57    char       *bid;
58    char       *bp, banner[80];
59    char        sn[6];
60
61    bp = banner;
62    memset (banner, 0, 80);         /* clear print buffer */
63
64    ci = (ci_t *)(netdev_priv(hi->ndev));
65    bid = sbeid_get_bdname (ci);
66    switch (hi->promfmt)
67    {
68    case PROM_FORMAT_TYPE1:
69        memcpy (sn, (FLD_TYPE1 *) (hi->mfg_info.pft1.Serial), 6);
70        break;
71    case PROM_FORMAT_TYPE2:
72        memcpy (sn, (FLD_TYPE2 *) (hi->mfg_info.pft2.Serial), 6);
73        break;
74    default:
75        memset (sn, 0, 6);
76        break;
77    }
78
79    sprintf (banner, "%s: %s  S/N %06X, MUSYCC Rev %02X",
80             hi->devname, bid,
81             ((sn[3] << 16) & 0xff0000) |
82              ((sn[4] << 8) & 0x00ff00) |
83              (sn[5] & 0x0000ff),
84             (u_int8_t) hi->revid[0]);
85
86    pr_info("%s\n", banner);
87
88    pdev = hi->pdev[0];
89    pr_info("%s: %s at v/p=%lx/%lx (%02x:%02x.%x) irq %d\n",
90            hi->devname, "MUSYCC",
91            (unsigned long) hi->addr_mapped[0], hi->addr[0],
92            hi->pci_busno, (u_int8_t) PCI_SLOT (pdev->devfn),
93            (u_int8_t) PCI_FUNC (pdev->devfn), pdev->irq);
94
95    pdev = hi->pdev[1];
96    pr_info("%s: %s at v/p=%lx/%lx (%02x:%02x.%x) irq %d\n",
97            hi->devname, "EBUS  ",
98            (unsigned long) hi->addr_mapped[1], hi->addr[1],
99            hi->pci_busno, (u_int8_t) PCI_SLOT (pdev->devfn),
100            (u_int8_t) PCI_FUNC (pdev->devfn), pdev->irq);
101}
102
103
104void        __init
105hdw_sn_get (hdw_info_t * hi, int brdno)
106{
107    /* obtain hardware EEPROM information */
108    long        addr;
109
110    addr = (long) hi->addr_mapped[1] + EEPROM_OFFSET;
111
112    /* read EEPROM with largest known format size... */
113    pmc_eeprom_read_buffer (addr, 0, (char *) hi->mfg_info.data, sizeof (FLD_TYPE2));
114
115
116    if ((hi->promfmt = pmc_verify_cksum (&hi->mfg_info.data)) == PROM_FORMAT_Unk)
117    {
118        /* bad crc, data is suspect */
119        if (log_level >= LOG_WARN)
120            pr_info("%s: EEPROM cksum error\n", hi->devname);
121        hi->mfg_info_sts = EEPROM_CRCERR;
122    } else
123        hi->mfg_info_sts = EEPROM_OK;
124}
125
126
127void        __init
128prep_hdw_info (void)
129{
130    hdw_info_t *hi;
131    int         i;
132
133    for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++)
134    {
135        hi->pci_busno = 0xff;
136        hi->pci_slot = 0xff;
137        hi->pci_pin[0] = 0;
138        hi->pci_pin[1] = 0;
139        hi->ndev = 0;
140        hi->addr[0] = 0L;
141        hi->addr[1] = 0L;
142        hi->addr_mapped[0] = 0L;
143        hi->addr_mapped[1] = 0L;
144    }
145}
146
147void
148cleanup_ioremap (void)
149{
150    hdw_info_t *hi;
151    int         i;
152
153    for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++)
154    {
155        if (hi->pci_slot == 0xff)
156            break;
157        if (hi->addr_mapped[0])
158        {
159            iounmap ((void *) (hi->addr_mapped[0]));
160            release_mem_region ((long) hi->addr[0], hi->len[0]);
161            hi->addr_mapped[0] = 0;
162        }
163        if (hi->addr_mapped[1])
164        {
165            iounmap ((void *) (hi->addr_mapped[1]));
166            release_mem_region ((long) hi->addr[1], hi->len[1]);
167            hi->addr_mapped[1] = 0;
168        }
169    }
170}
171
172
173void
174cleanup_devs (void)
175{
176    hdw_info_t *hi;
177    int         i;
178
179    for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++)
180    {
181        if (hi->pci_slot == 0xff || !hi->ndev)
182            break;
183        c4_stopwd(netdev_priv(hi->ndev));
184#ifdef CONFIG_PROC_FS
185        sbecom_proc_brd_cleanup(netdev_priv(hi->ndev));
186#endif
187        unregister_netdev (hi->ndev);
188        free_irq (hi->pdev[0]->irq, hi->ndev);
189#ifdef CONFIG_SBE_PMCC4_NCOMM
190        free_irq (hi->pdev[1]->irq, hi->ndev);
191#endif
192        OS_kfree (hi->ndev);
193    }
194}
195
196
197STATIC int  __init
198c4_hdw_init (struct pci_dev * pdev, int found)
199{
200    hdw_info_t *hi;
201    int         i;
202    int         fun, slot;
203    unsigned char busno = 0xff;
204
205    /* our MUSYCC chip supports two functions, 0 & 1 */
206    if ((fun = PCI_FUNC (pdev->devfn)) > 1)
207    {
208        pr_warning("unexpected devfun: 0x%x\n", pdev->devfn);
209        return 0;
210    }
211    if (pdev->bus)                  /* obtain bus number */
212        busno = pdev->bus->number;
213    else
214        busno = 0;                  /* default for system PCI inconsistency */
215    slot = pdev->devfn & ~0x07;
216
217    /*
218     * Functions 0 & 1 for a given board (identified by same bus(busno) and
219     * slot(slot)) are placed into the same 'hardware' structure.  The first
220     * part of the board's functionality will be placed into an unpopulated
221     * element, identified by "slot==(0xff)".  The second part of a board's
222     * functionality will match the previously loaded slot/busno.
223     */
224    for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++)
225    {
226        /*
227         * match with board's first found interface, otherwise this is first
228         * found
229         */
230        if ((hi->pci_slot == 0xff) ||   /* new board */
231            ((hi->pci_slot == slot) && (hi->bus == pdev->bus)))
232            break;                  /* found for-loop exit */
233    }
234    if (i == MAX_BOARDS)            /* no match in above loop means MAX
235                                     * exceeded */
236    {
237        pr_warning("exceeded number of allowed devices (>%d)?\n", MAX_BOARDS);
238        return 0;
239    }
240    if (pdev->bus)
241        hi->pci_busno = pdev->bus->number;
242    else
243        hi->pci_busno = 0;          /* default for system PCI inconsistency */
244    hi->pci_slot = slot;
245    pci_read_config_byte (pdev, PCI_INTERRUPT_PIN, &hi->pci_pin[fun]);
246    pci_read_config_byte (pdev, PCI_REVISION_ID, &hi->revid[fun]);
247    hi->bus = pdev->bus;
248    hi->addr[fun] = pci_resource_start (pdev, 0);
249    hi->len[fun] = pci_resource_end (pdev, 0) - hi->addr[fun] + 1;
250    hi->pdev[fun] = pdev;
251
252    {
253        /*
254         * create device name from module name, plus add the appropriate
255         * board number
256         */
257        char       *cp = hi->devname;
258
259        strcpy (cp, KBUILD_MODNAME);
260        cp += strlen (cp);          /* reposition */
261        *cp++ = '-';
262        *cp++ = '0' + (found / 2);  /* there are two found interfaces per
263                                     * board */
264        *cp = 0;                    /* termination */
265    }
266
267    return 1;
268}
269
270
271status_t    __init
272c4hw_attach_all (void)
273{
274    hdw_info_t *hi;
275    struct pci_dev *pdev = NULL;
276    int         found = 0, i, j;
277
278    error_flag = 0;
279    prep_hdw_info ();
280    /*** scan PCI bus for all possible boards */
281    while ((pdev = pci_get_device (PCI_VENDOR_ID_CONEXANT,
282                                    PCI_DEVICE_ID_CN8474,
283                                    pdev)))
284    {
285        if (c4_hdw_init (pdev, found))
286            found++;
287    }
288    if (!found)
289    {
290        pr_warning("No boards found\n");
291        return ENODEV;
292    }
293    /* sanity check for consistant hardware found */
294    for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++)
295    {
296        if (hi->pci_slot != 0xff && (!hi->addr[0] || !hi->addr[1]))
297        {
298            pr_warning("%s: something very wrong with pci_get_device\n",
299                       hi->devname);
300            return EIO;
301        }
302    }
303    /* bring board's memory regions on/line */
304    for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++)
305    {
306        if (hi->pci_slot == 0xff)
307            break;
308        for (j = 0; j < 2; j++)
309        {
310            if (request_mem_region (hi->addr[j], hi->len[j], hi->devname) == 0)
311            {
312                pr_warning("%s: memory in use, addr=0x%lx, len=0x%lx ?\n",
313                           hi->devname, hi->addr[j], hi->len[j]);
314                cleanup_ioremap ();
315                return ENOMEM;
316            }
317            hi->addr_mapped[j] = (unsigned long) ioremap (hi->addr[j], hi->len[j]);
318            if (!hi->addr_mapped[j])
319            {
320                pr_warning("%s: ioremap fails, addr=0x%lx, len=0x%lx ?\n",
321                           hi->devname, hi->addr[j], hi->len[j]);
322                cleanup_ioremap ();
323                return ENOMEM;
324            }
325#ifdef SBE_MAP_DEBUG
326            pr_warning("%s: io remapped from phys %x to virt %x\n",
327                       hi->devname, (u_int32_t) hi->addr[j], (u_int32_t) hi->addr_mapped[j]);
328#endif
329        }
330    }
331
332    drvr_state = SBE_DRVR_AVAILABLE;
333
334    /* Have now memory mapped all boards.  Now allow board's access to system */
335    for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++)
336    {
337        if (hi->pci_slot == 0xff)
338            break;
339        if (pci_enable_device (hi->pdev[0]) ||
340            pci_enable_device (hi->pdev[1]))
341        {
342            drvr_state = SBE_DRVR_DOWN;
343            pr_warning("%s: failed to enable card %d slot %d\n",
344                       hi->devname, i, hi->pci_slot);
345            cleanup_devs ();
346            cleanup_ioremap ();
347            return EIO;
348        }
349        pci_set_master (hi->pdev[0]);
350        pci_set_master (hi->pdev[1]);
351        if (!(hi->ndev = c4_add_dev (hi, i, (long) hi->addr_mapped[0],
352                                     (long) hi->addr_mapped[1],
353                                     hi->pdev[0]->irq,
354                                     hi->pdev[1]->irq)))
355        {
356            drvr_state = SBE_DRVR_DOWN;
357            cleanup_ioremap ();
358            /* NOTE: c4_add_dev() does its own device cleanup */
359            return error_flag;      /* error_flag set w/in add_dev() */
360        }
361        show_two (hi, i);           /* displays found information */
362    }
363    return 0;
364}
365
366/***  End-of-File  ***/
367