Commit | Line | Data |
---|---|---|
50ee11fe BB |
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 | ||
e6e4d05d JP |
15 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
16 | ||
50ee11fe BB |
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 | ||
40 | extern int log_level; | |
41 | extern int error_flag; | |
42 | extern int drvr_state; | |
43 | ||
44 | /* forward references */ | |
45 | void c4_stopwd (ci_t *); | |
46 | struct net_device * __init c4_add_dev (hdw_info_t *, int, unsigned long, unsigned long, int, int); | |
47 | ||
48 | ||
49 | struct s_hdw_info hdw_info[MAX_BOARDS]; | |
50 | ||
51 | ||
52 | void __init | |
53 | show_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 | ||
694a9807 | 86 | pr_info("%s\n", banner); |
50ee11fe BB |
87 | |
88 | pdev = hi->pdev[0]; | |
694a9807 | 89 | pr_info("%s: %s at v/p=%lx/%lx (%02x:%02x.%x) irq %d\n", |
50ee11fe BB |
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]; | |
694a9807 | 96 | pr_info("%s: %s at v/p=%lx/%lx (%02x:%02x.%x) irq %d\n", |
50ee11fe BB |
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 | ||
104 | void __init | |
105 | hdw_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 | #if 0 | |
116 | { | |
117 | unsigned char *ucp = (unsigned char *) &hi->mfg_info.data; | |
118 | ||
694a9807 | 119 | pr_info("eeprom[00]: %02x %02x %02x %02x %02x %02x %02x %02x\n", |
50ee11fe | 120 | *(ucp + 0), *(ucp + 1), *(ucp + 2), *(ucp + 3), *(ucp + 4), *(ucp + 5), *(ucp + 6), *(ucp + 7)); |
694a9807 | 121 | pr_info("eeprom[08]: %02x %02x %02x %02x %02x %02x %02x %02x\n", |
50ee11fe | 122 | *(ucp + 8), *(ucp + 9), *(ucp + 10), *(ucp + 11), *(ucp + 12), *(ucp + 13), *(ucp + 14), *(ucp + 15)); |
694a9807 | 123 | pr_info("eeprom[16]: %02x %02x %02x %02x %02x %02x %02x %02x\n", |
50ee11fe | 124 | *(ucp + 16), *(ucp + 17), *(ucp + 18), *(ucp + 19), *(ucp + 20), *(ucp + 21), *(ucp + 22), *(ucp + 23)); |
694a9807 | 125 | pr_info("eeprom[24]: %02x %02x %02x %02x %02x %02x %02x %02x\n", |
50ee11fe | 126 | *(ucp + 24), *(ucp + 25), *(ucp + 26), *(ucp + 27), *(ucp + 28), *(ucp + 29), *(ucp + 30), *(ucp + 31)); |
694a9807 | 127 | pr_info("eeprom[32]: %02x %02x %02x %02x %02x %02x %02x %02x\n", |
50ee11fe | 128 | *(ucp + 32), *(ucp + 33), *(ucp + 34), *(ucp + 35), *(ucp + 36), *(ucp + 37), *(ucp + 38), *(ucp + 39)); |
694a9807 | 129 | pr_info("eeprom[40]: %02x %02x %02x %02x %02x %02x %02x %02x\n", |
50ee11fe BB |
130 | *(ucp + 40), *(ucp + 41), *(ucp + 42), *(ucp + 43), *(ucp + 44), *(ucp + 45), *(ucp + 46), *(ucp + 47)); |
131 | } | |
132 | #endif | |
133 | #if 0 | |
694a9807 | 134 | pr_info("sn: %x %x %x %x %x %x\n", |
50ee11fe BB |
135 | hi->mfg_info.Serial[0], |
136 | hi->mfg_info.Serial[1], | |
137 | hi->mfg_info.Serial[2], | |
138 | hi->mfg_info.Serial[3], | |
139 | hi->mfg_info.Serial[4], | |
140 | hi->mfg_info.Serial[5]); | |
141 | #endif | |
142 | ||
143 | if ((hi->promfmt = pmc_verify_cksum (&hi->mfg_info.data)) == PROM_FORMAT_Unk) | |
144 | { | |
145 | /* bad crc, data is suspect */ | |
146 | if (log_level >= LOG_WARN) | |
694a9807 | 147 | pr_info("%s: EEPROM cksum error\n", hi->devname); |
50ee11fe BB |
148 | hi->mfg_info_sts = EEPROM_CRCERR; |
149 | } else | |
150 | hi->mfg_info_sts = EEPROM_OK; | |
151 | } | |
152 | ||
153 | ||
154 | void __init | |
155 | prep_hdw_info (void) | |
156 | { | |
157 | hdw_info_t *hi; | |
158 | int i; | |
159 | ||
160 | for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) | |
161 | { | |
162 | hi->pci_busno = 0xff; | |
163 | hi->pci_slot = 0xff; | |
164 | hi->pci_pin[0] = 0; | |
165 | hi->pci_pin[1] = 0; | |
166 | hi->ndev = 0; | |
167 | hi->addr[0] = 0L; | |
168 | hi->addr[1] = 0L; | |
169 | hi->addr_mapped[0] = 0L; | |
170 | hi->addr_mapped[1] = 0L; | |
171 | } | |
172 | } | |
173 | ||
174 | void | |
175 | cleanup_ioremap (void) | |
176 | { | |
177 | hdw_info_t *hi; | |
178 | int i; | |
179 | ||
180 | for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) | |
181 | { | |
182 | if (hi->pci_slot == 0xff) | |
183 | break; | |
184 | if (hi->addr_mapped[0]) | |
185 | { | |
186 | iounmap ((void *) (hi->addr_mapped[0])); | |
187 | release_mem_region ((long) hi->addr[0], hi->len[0]); | |
188 | hi->addr_mapped[0] = 0; | |
189 | } | |
190 | if (hi->addr_mapped[1]) | |
191 | { | |
192 | iounmap ((void *) (hi->addr_mapped[1])); | |
193 | release_mem_region ((long) hi->addr[1], hi->len[1]); | |
194 | hi->addr_mapped[1] = 0; | |
195 | } | |
196 | } | |
197 | } | |
198 | ||
199 | ||
200 | void | |
201 | cleanup_devs (void) | |
202 | { | |
203 | hdw_info_t *hi; | |
204 | int i; | |
205 | ||
206 | for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) | |
207 | { | |
208 | if (hi->pci_slot == 0xff || !hi->ndev) | |
209 | break; | |
210 | c4_stopwd(netdev_priv(hi->ndev)); | |
211 | #ifdef CONFIG_PROC_FS | |
212 | sbecom_proc_brd_cleanup(netdev_priv(hi->ndev)); | |
213 | #endif | |
214 | unregister_netdev (hi->ndev); | |
215 | free_irq (hi->pdev[0]->irq, hi->ndev); | |
216 | #ifdef CONFIG_SBE_PMCC4_NCOMM | |
217 | free_irq (hi->pdev[1]->irq, hi->ndev); | |
218 | #endif | |
219 | OS_kfree (hi->ndev); | |
220 | } | |
221 | } | |
222 | ||
223 | ||
224 | STATIC int __init | |
225 | c4_hdw_init (struct pci_dev * pdev, int found) | |
226 | { | |
227 | hdw_info_t *hi; | |
228 | int i; | |
229 | int fun, slot; | |
230 | unsigned char busno = 0xff; | |
231 | ||
232 | /* our MUSYCC chip supports two functions, 0 & 1 */ | |
233 | if ((fun = PCI_FUNC (pdev->devfn)) > 1) | |
234 | { | |
e6e4d05d | 235 | pr_warning("unexpected devfun: 0x%x\n", pdev->devfn); |
50ee11fe BB |
236 | return 0; |
237 | } | |
238 | if (pdev->bus) /* obtain bus number */ | |
239 | busno = pdev->bus->number; | |
240 | else | |
241 | busno = 0; /* default for system PCI inconsistency */ | |
242 | slot = pdev->devfn & ~0x07; | |
243 | ||
244 | /* | |
245 | * Functions 0 & 1 for a given board (identified by same bus(busno) and | |
246 | * slot(slot)) are placed into the same 'hardware' structure. The first | |
247 | * part of the board's functionality will be placed into an unpopulated | |
248 | * element, identified by "slot==(0xff)". The second part of a board's | |
249 | * functionality will match the previously loaded slot/busno. | |
250 | */ | |
251 | for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) | |
252 | { | |
253 | /* | |
254 | * match with board's first found interface, otherwise this is first | |
255 | * found | |
256 | */ | |
257 | if ((hi->pci_slot == 0xff) || /* new board */ | |
258 | ((hi->pci_slot == slot) && (hi->bus == pdev->bus))) | |
259 | break; /* found for-loop exit */ | |
260 | } | |
261 | if (i == MAX_BOARDS) /* no match in above loop means MAX | |
262 | * exceeded */ | |
263 | { | |
e6e4d05d | 264 | pr_warning("exceeded number of allowed devices (>%d)?\n", MAX_BOARDS); |
50ee11fe BB |
265 | return 0; |
266 | } | |
267 | if (pdev->bus) | |
268 | hi->pci_busno = pdev->bus->number; | |
269 | else | |
270 | hi->pci_busno = 0; /* default for system PCI inconsistency */ | |
271 | hi->pci_slot = slot; | |
272 | pci_read_config_byte (pdev, PCI_INTERRUPT_PIN, &hi->pci_pin[fun]); | |
273 | pci_read_config_byte (pdev, PCI_REVISION_ID, &hi->revid[fun]); | |
274 | hi->bus = pdev->bus; | |
275 | hi->addr[fun] = pci_resource_start (pdev, 0); | |
276 | hi->len[fun] = pci_resource_end (pdev, 0) - hi->addr[fun] + 1; | |
277 | hi->pdev[fun] = pdev; | |
278 | ||
279 | { | |
280 | /* | |
281 | * create device name from module name, plus add the appropriate | |
282 | * board number | |
283 | */ | |
284 | char *cp = hi->devname; | |
285 | ||
40447df8 | 286 | strcpy (cp, KBUILD_MODNAME); |
50ee11fe BB |
287 | cp += strlen (cp); /* reposition */ |
288 | *cp++ = '-'; | |
289 | *cp++ = '0' + (found / 2); /* there are two found interfaces per | |
290 | * board */ | |
291 | *cp = 0; /* termination */ | |
292 | } | |
293 | ||
294 | return 1; | |
295 | } | |
296 | ||
297 | ||
298 | status_t __init | |
299 | c4hw_attach_all (void) | |
300 | { | |
301 | hdw_info_t *hi; | |
302 | struct pci_dev *pdev = NULL; | |
303 | int found = 0, i, j; | |
304 | ||
305 | error_flag = 0; | |
306 | prep_hdw_info (); | |
307 | /*** scan PCI bus for all possible boards */ | |
50ee11fe | 308 | while ((pdev = pci_get_device (PCI_VENDOR_ID_CONEXANT, |
50ee11fe BB |
309 | PCI_DEVICE_ID_CN8474, |
310 | pdev))) | |
50ee11fe BB |
311 | { |
312 | if (c4_hdw_init (pdev, found)) | |
313 | found++; | |
314 | } | |
315 | if (!found) | |
316 | { | |
e6e4d05d | 317 | pr_warning("No boards found\n"); |
50ee11fe BB |
318 | return ENODEV; |
319 | } | |
320 | /* sanity check for consistant hardware found */ | |
321 | for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) | |
322 | { | |
323 | if (hi->pci_slot != 0xff && (!hi->addr[0] || !hi->addr[1])) | |
324 | { | |
e6e4d05d JP |
325 | pr_warning("%s: something very wrong with pci_get_device\n", |
326 | hi->devname); | |
50ee11fe BB |
327 | return EIO; |
328 | } | |
329 | } | |
330 | /* bring board's memory regions on/line */ | |
331 | for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) | |
332 | { | |
333 | if (hi->pci_slot == 0xff) | |
334 | break; | |
335 | for (j = 0; j < 2; j++) | |
336 | { | |
337 | if (request_mem_region (hi->addr[j], hi->len[j], hi->devname) == 0) | |
338 | { | |
e6e4d05d JP |
339 | pr_warning("%s: memory in use, addr=0x%lx, len=0x%lx ?\n", |
340 | hi->devname, hi->addr[j], hi->len[j]); | |
50ee11fe BB |
341 | cleanup_ioremap (); |
342 | return ENOMEM; | |
343 | } | |
344 | hi->addr_mapped[j] = (unsigned long) ioremap (hi->addr[j], hi->len[j]); | |
345 | if (!hi->addr_mapped[j]) | |
346 | { | |
e6e4d05d JP |
347 | pr_warning("%s: ioremap fails, addr=0x%lx, len=0x%lx ?\n", |
348 | hi->devname, hi->addr[j], hi->len[j]); | |
50ee11fe BB |
349 | cleanup_ioremap (); |
350 | return ENOMEM; | |
351 | } | |
352 | #ifdef SBE_MAP_DEBUG | |
e6e4d05d JP |
353 | pr_warning("%s: io remapped from phys %x to virt %x\n", |
354 | hi->devname, (u_int32_t) hi->addr[j], (u_int32_t) hi->addr_mapped[j]); | |
50ee11fe BB |
355 | #endif |
356 | } | |
357 | } | |
358 | ||
359 | drvr_state = SBE_DRVR_AVAILABLE; | |
360 | ||
361 | /* Have now memory mapped all boards. Now allow board's access to system */ | |
362 | for (i = 0, hi = hdw_info; i < MAX_BOARDS; i++, hi++) | |
363 | { | |
364 | if (hi->pci_slot == 0xff) | |
365 | break; | |
366 | if (pci_enable_device (hi->pdev[0]) || | |
367 | pci_enable_device (hi->pdev[1])) | |
368 | { | |
369 | drvr_state = SBE_DRVR_DOWN; | |
e6e4d05d JP |
370 | pr_warning("%s: failed to enable card %d slot %d\n", |
371 | hi->devname, i, hi->pci_slot); | |
50ee11fe BB |
372 | cleanup_devs (); |
373 | cleanup_ioremap (); | |
374 | return EIO; | |
375 | } | |
376 | pci_set_master (hi->pdev[0]); | |
377 | pci_set_master (hi->pdev[1]); | |
378 | if (!(hi->ndev = c4_add_dev (hi, i, (long) hi->addr_mapped[0], | |
379 | (long) hi->addr_mapped[1], | |
380 | hi->pdev[0]->irq, | |
381 | hi->pdev[1]->irq))) | |
382 | { | |
383 | drvr_state = SBE_DRVR_DOWN; | |
384 | cleanup_ioremap (); | |
385 | /* NOTE: c4_add_dev() does its own device cleanup */ | |
386 | #if 0 | |
387 | cleanup_devs (); | |
388 | #endif | |
389 | return error_flag; /* error_flag set w/in add_dev() */ | |
390 | } | |
391 | show_two (hi, i); /* displays found information */ | |
392 | } | |
393 | return 0; | |
394 | } | |
395 | ||
396 | /*** End-of-File ***/ |