patch-2.4.4 linux/drivers/net/wan/sdladrv.c
Next file: linux/drivers/net/wan/sdlamain.c
Previous file: linux/drivers/net/wan/sdla_x25.c
Back to the patch index
Back to the overall index
- Lines: 928
- Date:
Thu Apr 12 12:11:39 2001
- Orig file:
v2.4.3/linux/drivers/net/wan/sdladrv.c
- Orig date:
Tue Mar 6 19:44:37 2001
diff -u --recursive --new-file v2.4.3/linux/drivers/net/wan/sdladrv.c linux/drivers/net/wan/sdladrv.c
@@ -6,13 +6,19 @@
*
* Author: Gideon Hack
*
-* Copyright: (c) 1995-1999 Sangoma Technologies Inc.
+* Copyright: (c) 1995-2000 Sangoma Technologies Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
* ============================================================================
+* Mar 20, 2001 Nenad Corbic Added the auto_pci_cfg filed, to support
+* the PCISLOT #0.
+* Apr 04, 2000 Nenad Corbic Fixed the auto memory detection code.
+* The memory test at address 0xC8000.
+* Mar 09, 2000 Nenad Corbic Added Gideon's Bug Fix: clear pci
+* interrupt flags on initial load.
* Jun 02, 1999 Gideon Hack Added support for the S514 adapter.
* Updates for Linux 2.2.X kernels.
* Sep 17, 1998 Jaspreet Singh Updates for linux 2.2.X kernels
@@ -84,7 +90,6 @@
#if defined(_LINUX_) /****** Linux *******************************/
-#include <linux/config.h>
#include <linux/version.h>
#include <linux/kernel.h> /* printk(), and other useful stuff */
#include <linux/stddef.h> /* offsetof(), etc. */
@@ -102,7 +107,16 @@
#define _OUTB(port, byte) (outb((byte),(port)))
#define SYSTEM_TICK jiffies
-#include <linux/init.h>
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+ #include <linux/init.h>
+#else
+ #include <linux/bios32.h>/* BIOS32, PCI BIOS functions and definitions */
+ #define ioremap vremap
+ #define iounmap vfree
+ extern void * vremap (unsigned long offset, unsigned long size);
+ extern void vfree (void *addr);
+#endif
#elif defined(_SCO_UNIX_) /****** SCO Unix ****************************/
@@ -190,16 +204,21 @@
static unsigned check_memregion (void* ptr, unsigned len);
static unsigned test_memregion (void* ptr, unsigned len);
static unsigned short checksum (unsigned char* buf, unsigned len);
+static int init_pci_slot(sdlahw_t *);
+
+static int pci_probe(sdlahw_t *hw);
/****** Global Data **********************************************************
* Note: All data must be explicitly initialized!!!
*/
+#ifdef LINUX_2_4
static struct pci_device_id sdladrv_pci_tbl[] __initdata = {
{ V3_VENDOR_ID, V3_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(pci, sdladrv_pci_tbl);
+#endif
/* private data */
static char modname[] = "sdladrv";
@@ -298,6 +317,8 @@
0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xE0
};
+static int pci_slot_ar[MAX_S514_CARDS];
+
/******* Kernel Loadable Module Entry Points ********************************/
/*============================================================================
@@ -314,15 +335,24 @@
#ifdef MODULE
int init_module (void)
#else
-int __init wanpipe_init(void)
+int sdladrv_init(void)
#endif
{
+ int i=0;
+
printk(KERN_INFO "%s v%u.%u %s\n",
fullname, MOD_VERSION, MOD_RELEASE, copyright);
exec_idle = calibrate_delay(EXEC_DELAY);
#ifdef WANDEBUG
printk(KERN_DEBUG "%s: exec_idle = %d\n", modname, exec_idle);
#endif
+
+ /* Initialize the PCI Card array, which
+ * will store flags, used to mark
+ * card initialization state */
+ for (i=0; i<MAX_S514_CARDS; i++)
+ pci_slot_ar[i] = 0xFF;
+
return 0;
}
@@ -350,7 +380,9 @@
* < 0 error
*/
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
EXPORT_SYMBOL(sdla_setup);
+#endif
int sdla_setup (sdlahw_t* hw, void* sfm, unsigned len)
{
@@ -361,7 +393,7 @@
if (sdla_detect(hw)) {
if(hw->type != SDLA_S514)
- printk(KERN_ERR "%s: no SDLA card found at port 0x%X\n",
+ printk(KERN_INFO "%s: no SDLA card found at port 0x%X\n",
modname, hw->port);
return -EINVAL;
}
@@ -410,7 +442,7 @@
/* Verify IRQ configuration options */
if (!get_option_index(irq_opt, hw->irq)) {
- printk(KERN_ERR "%s: IRQ %d is illegal!\n",
+ printk(KERN_INFO "%s: IRQ %d is illegal!\n",
modname, hw->irq);
return -EINVAL;
}
@@ -420,7 +452,7 @@
hw->pclk = pclk_opt[1]; /* use default */
else if (!get_option_index(pclk_opt, hw->pclk)) {
- printk(KERN_ERR "%s: CPU clock %u is illegal!\n",
+ printk(KERN_INFO "%s: CPU clock %u is illegal!\n",
modname, hw->pclk);
return -EINVAL;
}
@@ -431,7 +463,7 @@
if (hw->dpmbase == 0) {
err = sdla_autodpm(hw);
if (err) {
- printk(KERN_ERR
+ printk(KERN_INFO
"%s: can't find available memory region!\n",
modname);
return err;
@@ -439,13 +471,13 @@
}
else if (!get_option_index(dpmbase_opt,
virt_to_phys(hw->dpmbase))) {
- printk(KERN_ERR
+ printk(KERN_INFO
"%s: memory address 0x%lX is illegal!\n",
modname, virt_to_phys(hw->dpmbase));
return -EINVAL;
}
else if (sdla_setdpm(hw)) {
- printk(KERN_ERR
+ printk(KERN_INFO
"%s: 8K memory region at 0x%lX is not available!\n",
modname, virt_to_phys(hw->dpmbase));
return -EINVAL;
@@ -453,13 +485,27 @@
printk(KERN_INFO
"%s: dual-port memory window is set at 0x%lX.\n",
modname, virt_to_phys(hw->dpmbase));
+
+
+ /* If we find memory in 0xE**** Memory region,
+ * warn the user to disable the SHADOW RAM.
+ * Since memory corruption can occur if SHADOW is
+ * enabled. This can causes random crashes ! */
+ if (virt_to_phys(hw->dpmbase) >= 0xE0000){
+ printk(KERN_WARNING "\n%s: !!!!!!!! WARNING !!!!!!!!\n",modname);
+ printk(KERN_WARNING "%s: WANPIPE is using 0x%lX memory region !!!\n",
+ modname, virt_to_phys(hw->dpmbase));
+ printk(KERN_WARNING " Please disable the SHADOW RAM, otherwise\n");
+ printk(KERN_WARNING " your system might crash randomly from time to time !\n");
+ printk(KERN_WARNING "%s: !!!!!!!! WARNING !!!!!!!!\n\n",modname);
+ }
}
else {
hw->memory = test_memregion((void*)hw->dpmbase,
MAX_SIZEOF_S514_MEMORY);
if(hw->memory < (256 * 1024)) {
- printk(KERN_ERR
+ printk(KERN_INFO
"%s: error in testing S514 memory (0x%lX)\n",
modname, hw->memory);
sdla_down(hw);
@@ -481,7 +527,9 @@
* Shut down SDLA: disable shared memory access and interrupts, stop CPU, etc.
*/
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
EXPORT_SYMBOL(sdla_down);
+#endif
int sdla_down (sdlahw_t* hw)
{
@@ -523,9 +571,10 @@
*(char *)hw->vector = S514_CPU_HALT;
CPU_no = hw->S514_cpu_no[0];
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
/* disable the PCI IRQ and disable memory access */
pci_read_config_dword(hw->pci_dev, PCI_INT_CONFIG, &int_config);
- int_config &= (CPU_no == S514_CPU_A) ? ~PCI_DISABLE_IRQ_CPU_A : ~PCI_DISABLE_IRQ_CPU_B;
+ int_config &= (CPU_no == S514_CPU_A) ? ~PCI_DISABLE_IRQ_CPU_A : ~PCI_DISABLE_IRQ_CPU_B;
pci_write_config_dword(hw->pci_dev, PCI_INT_CONFIG, int_config);
read_S514_int_stat(hw, &int_status);
S514_intack(hw, int_status);
@@ -535,6 +584,22 @@
else
pci_write_config_dword(hw->pci_dev, PCI_MAP1_DWORD,
PCI_CPU_B_MEM_DISABLE);
+#else
+ /* disable the PCI IRQ and disable memory access */
+ pcibios_read_config_dword(hw->pci_bus, hw->pci_dev_func,
+ PCI_INT_CONFIG, &int_config);
+ int_config &= (CPU_no == S514_CPU_A) ? ~PCI_DISABLE_IRQ_CPU_A : ~PCI_DISABLE_IRQ_CPU_B;
+ pcibios_write_config_dword(hw->pci_bus, hw->pci_dev_func,
+ PCI_INT_CONFIG, int_config);
+ read_S514_int_stat(hw, &int_status);
+ S514_intack(hw, int_status);
+ // disable PCI memory access
+ if(CPU_no == S514_CPU_A)
+ pcibios_write_config_dword(hw->pci_bus,hw->pci_dev_func,
+ PCI_MAP0_DWORD, PCI_CPU_A_MEM_DISABLE);
+ else
+ pcibios_write_config_dword(hw->pci_bus,hw->pci_dev_func, PCI_MAP1_DWORD, PCI_CPU_B_MEM_DISABLE);
+#endif
/* free up the allocated virtual memory */
iounmap((void *)hw->dpmbase);
@@ -552,7 +617,9 @@
* Map shared memory window into SDLA address space.
*/
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
EXPORT_SYMBOL(sdla_mapmem);
+#endif
int sdla_mapmem (sdlahw_t* hw, unsigned long addr)
{
@@ -613,7 +680,9 @@
* Enable interrupt generation.
*/
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
EXPORT_SYMBOL(sdla_inten);
+#endif
int sdla_inten (sdlahw_t* hw)
{
@@ -669,7 +738,9 @@
* Disable interrupt generation.
*/
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
EXPORT_SYMBOL(sdla_intde);
+#endif
int sdla_intde (sdlahw_t* hw)
{
@@ -724,7 +795,9 @@
* Acknowledge SDLA hardware interrupt.
*/
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
EXPORT_SYMBOL(sdla_intack);
+#endif
int sdla_intack (sdlahw_t* hw)
{
@@ -774,11 +847,18 @@
* Acknowledge S514 hardware interrupt.
*/
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
EXPORT_SYMBOL(S514_intack);
+#endif
void S514_intack (sdlahw_t* hw, u32 int_status)
{
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
pci_write_config_dword(hw->pci_dev, PCI_INT_STATUS, int_status);
+#else
+ pcibios_write_config_dword(hw->pci_bus, hw->pci_dev_func,
+ PCI_INT_STATUS, int_status);
+#endif
}
@@ -786,11 +866,18 @@
* Read the S514 hardware interrupt status.
*/
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
EXPORT_SYMBOL(read_S514_int_stat);
+#endif
void read_S514_int_stat (sdlahw_t* hw, u32* int_status)
{
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
pci_read_config_dword(hw->pci_dev, PCI_INT_STATUS, int_status);
+#else
+ pcibios_read_config_dword(hw->pci_bus, hw->pci_dev_func, PCI_INT_STATUS,
+ int_status);
+#endif
}
@@ -798,7 +885,9 @@
* Generate an interrupt to adapter's CPU.
*/
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
EXPORT_SYMBOL(sdla_intr);
+#endif
int sdla_intr (sdlahw_t* hw)
{
@@ -842,7 +931,9 @@
* o Return number of loops made, or 0 if command timed out.
*/
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
EXPORT_SYMBOL(sdla_exec);
+#endif
int sdla_exec (void* opflag)
{
@@ -878,7 +969,9 @@
* interrupt routines are accessing adapter shared memory.
*/
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
EXPORT_SYMBOL(sdla_peek);
+#endif
int sdla_peek (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len)
{
@@ -960,7 +1053,9 @@
* interrupt routines are accessing adapter shared memory.
*/
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
EXPORT_SYMBOL(sdla_poke);
+#endif
int sdla_poke (sdlahw_t* hw, unsigned long addr, void* buf, unsigned len)
{
@@ -1124,7 +1219,11 @@
return -EINVAL;
}
- for (i = opt[0]; i && err; --i) {
+ /* Start testing from 8th position, address
+ * 0xC8000 from the 508 address table.
+ * We don't want to test A**** addresses, since
+ * they are usually used for Video */
+ for (i = 8; i <= opt[0] && err; i++) {
hw->dpmbase = phys_to_virt(opt[i]);
err = sdla_setdpm(hw);
}
@@ -1176,14 +1275,14 @@
/* Verify firmware signature */
if (strcmp(sfm->signature, SFM_SIGNATURE)) {
- printk(KERN_ERR "%s: not SDLA firmware!\n",
+ printk(KERN_INFO "%s: not SDLA firmware!\n",
modname);
return -EINVAL;
}
/* Verify firmware module format version */
if (sfm->version != SFM_VERSION) {
- printk(KERN_ERR
+ printk(KERN_INFO
"%s: firmware format %u rejected! Expecting %u.\n",
modname, sfm->version, SFM_VERSION);
return -EINVAL;
@@ -1193,7 +1292,7 @@
if ((len - offsetof(sfm_t, image) != sfm->info.codesize) ||
(checksum((void*)&sfm->info,
sizeof(sfm_info_t) + sfm->info.codesize) != sfm->checksum)) {
- printk(KERN_ERR "%s: firmware corrupted!\n", modname);
+ printk(KERN_INFO "%s: firmware corrupted!\n", modname);
return -EINVAL;
}
@@ -1211,19 +1310,18 @@
*/
for (i = 0;
(i < SFM_MAX_SDLA) && (sfm->info.adapter[i] != hw->type);
- ++i)
- ;
+ ++i);
+
if (i == SFM_MAX_SDLA) {
- printk(KERN_ERR "%s: firmware is not compatible with S%u!\n",
+ printk(KERN_INFO "%s: firmware is not compatible with S%u!\n",
modname, hw->type);
- ;
return -EINVAL;
}
/* Make sure there is enough on-board memory */
if (hw->memory < sfm->info.memsize) {
- printk(KERN_ERR
+ printk(KERN_INFO
"%s: firmware needs %lu bytes of on-board memory!\n",
modname, sfm->info.memsize);
return -EINVAL;
@@ -1231,7 +1329,7 @@
/* Move code onto adapter */
if (sdla_poke(hw, sfm->info.codeoffs, sfm->image, sfm->info.codesize)) {
- printk(KERN_ERR "%s: failed to load code segment!\n",
+ printk(KERN_INFO "%s: failed to load code segment!\n",
modname);
return -EIO;
}
@@ -1239,14 +1337,14 @@
/* Prepare boot-time configuration data and kick-off CPU */
sdla_bootcfg(hw, &sfm->info);
if (sdla_start(hw, sfm->info.startoffs)) {
- printk(KERN_ERR "%s: Damn... Adapter won't start!\n",
+ printk(KERN_INFO "%s: Damn... Adapter won't start!\n",
modname);
return -EIO;
}
/* position DPM window over the mailbox and enable interrupts */
if (sdla_mapmem(hw, sfm->info.winoffs) || sdla_inten(hw)) {
- printk(KERN_ERR "%s: adapter hardware failure!\n",
+ printk(KERN_INFO "%s: adapter hardware failure!\n",
modname);
return -EIO;
}
@@ -1858,22 +1956,30 @@
*/
static int detect_s514 (sdlahw_t* hw)
{
- unsigned char CPU_no, slot_no;
+ unsigned char CPU_no, slot_no, auto_slot_cfg;
int number_S514_cards = 0;
u32 S514_mem_base_addr = 0;
u32 ut_u32;
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
struct pci_dev *pci_dev;
+#else
+ u8 ut_u8;
+#endif
#ifdef CONFIG_PCI
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
if(!pci_present())
+#else
+ if(!pcibios_present())
+#endif
{
- printk(KERN_ERR "%s: PCI BIOS not present!\n", modname);
+ printk(KERN_INFO "%s: PCI BIOS not present!\n", modname);
return 0;
}
#else
- printk(KERN_ERR "%s: Linux not compiled for PCI usage!\n", modname);
+ printk(KERN_INFO "%s: Linux not compiled for PCI usage!\n", modname);
return 0;
#endif
@@ -1883,10 +1989,17 @@
*/
CPU_no = hw->S514_cpu_no[0];
slot_no = hw->S514_slot_no;
-
- printk(KERN_INFO "%s: detecting S514 card, CPU %c, slot #%d\n",
- modname, CPU_no, slot_no);
+ auto_slot_cfg = hw->auto_pci_cfg;
+ if (auto_slot_cfg){
+ printk(KERN_INFO "%s: srch... S514 card, CPU %c, Slot=Auto\n",
+ modname, CPU_no);
+
+ }else{
+ printk(KERN_INFO "%s: srch... S514 card, CPU %c, Slot #%d\n",
+ modname, CPU_no, slot_no);
+ }
+
/* check to see that CPU A or B has been selected in 'router.conf' */
switch(CPU_no) {
case S514_CPU_A:
@@ -1894,9 +2007,9 @@
break;
default:
- printk(KERN_ERR "%s: S514 CPU definition invalid.\n",
+ printk(KERN_INFO "%s: S514 CPU definition invalid.\n",
modname);
- printk(KERN_ERR "Must be 'A' or 'B'\n");
+ printk(KERN_INFO "Must be 'A' or 'B'\n");
return 0;
}
@@ -1904,50 +2017,110 @@
if(!number_S514_cards)
return 0;
- /* we are using a single S514 adapter with a slot of 0 so re-read the */ /* location of this adapter */
- if((number_S514_cards == 1) && !slot_no) {
+ /* we are using a single S514 adapter with a slot of 0 so re-read the */
+ /* location of this adapter */
+ if((number_S514_cards == 1) && auto_slot_cfg) {
number_S514_cards = find_s514_adapter(hw, 1);
if(!number_S514_cards) {
- printk(KERN_ERR "%s: Error finding PCI card\n",
+ printk(KERN_INFO "%s: Error finding PCI card\n",
modname);
return 0;
}
}
+ #if defined(LINUX_2_4)
pci_dev = hw->pci_dev;
/* read the physical memory base address */
S514_mem_base_addr = (CPU_no == S514_CPU_A) ?
(pci_dev->resource[1].start) :
(pci_dev->resource[2].start);
+
+ #elif defined (LINUX_2_1)
+ pci_dev = hw->pci_dev;
+ /* read the physical memory base address */
+ S514_mem_base_addr = (CPU_no == S514_CPU_A) ?
+ (pci_dev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK) :
+ (pci_dev->base_address[2] & PCI_BASE_ADDRESS_MEM_MASK);
+
+ #else
+ pcibios_read_config_dword(hw->pci_bus, hw->pci_dev_func,
+ (CPU_no == S514_CPU_A) ? PCI_MEM_BASE0_DWORD :
+ PCI_MEM_BASE1_DWORD, &S514_mem_base_addr);
+ #endif
printk(KERN_INFO "%s: S514 PCI memory at 0x%X\n",
modname, S514_mem_base_addr);
if(!S514_mem_base_addr) {
if(CPU_no == S514_CPU_B)
- printk(KERN_ERR "%s: CPU #B not present on the card\n", modname);
+ printk(KERN_INFO "%s: CPU #B not present on the card\n", modname);
else
- printk(KERN_ERR "%s: No PCI memory allocated to card\n", modname);
+ printk(KERN_INFO "%s: No PCI memory allocated to card\n", modname);
return 0;
}
/* enable the PCI memory */
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
pci_read_config_dword(pci_dev,
(CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD,
&ut_u32);
pci_write_config_dword(pci_dev,
(CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD,
(ut_u32 | PCI_MEMORY_ENABLE));
+#else
+ pcibios_read_config_dword(hw->pci_bus, hw->pci_dev_func,
+ (CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD,
+ &ut_u32);
+ pcibios_write_config_dword(hw->pci_bus, hw->pci_dev_func,
+ (CPU_no == S514_CPU_A) ? PCI_MAP0_DWORD : PCI_MAP1_DWORD,
+ (ut_u32 | PCI_MEMORY_ENABLE));
+#endif
/* check the IRQ allocated and enable IRQ usage */
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
if(!(hw->irq = pci_dev->irq)) {
- printk(KERN_ERR "%s: IRQ not allocated to S514 adapter\n",
+ printk(KERN_INFO "%s: IRQ not allocated to S514 adapter\n",
modname);
return 0;
}
+
+ /* BUG FIX : Mar 6 2000
+ * On a initial loading of the card, we must check
+ * and clear PCI interrupt bits, due to a reset
+ * problem on some other boards. i.e. An interrupt
+ * might be pending, even after system bootup,
+ * in which case, when starting wanrouter the machine
+ * would crash.
+ */
+ if (init_pci_slot(hw))
+ return 0;
+
pci_read_config_dword(pci_dev, PCI_INT_CONFIG, &ut_u32);
ut_u32 |= (CPU_no == S514_CPU_A) ?
PCI_ENABLE_IRQ_CPU_A : PCI_ENABLE_IRQ_CPU_B;
pci_write_config_dword(pci_dev, PCI_INT_CONFIG, ut_u32);
+#else
+ /* the INTPIN must not be 0 - if it is, then the S514 adapter is not */
+ /* configured for IRQ usage */
+ pcibios_read_config_byte(hw->pci_bus, hw->pci_dev_func,
+ PCI_INT_PIN_BYTE, &ut_u8);
+ if(!ut_u8) {
+ printk(KERN_INFO "%s: invalid setting for INTPIN on S514 card\n", modname);
+ printk(KERN_INFO "Please contact your Sangoma representative\n");
+ return 0;
+ }
+ pcibios_read_config_byte(hw->pci_bus, hw->pci_dev_func,
+ PCI_INT_LINE_BYTE, (unsigned char *)&hw->irq);
+ if(hw->irq == PCI_IRQ_NOT_ALLOCATED) {
+ printk(KERN_INFO "%s: IRQ not allocated to S514 adapter\n",
+ modname);
+ return 0;
+ }
+ pcibios_read_config_dword(hw->pci_bus, hw->pci_dev_func, PCI_INT_CONFIG, &ut_u32);
+ ut_u32 |= (CPU_no == S514_CPU_A) ?
+ PCI_ENABLE_IRQ_CPU_A : PCI_ENABLE_IRQ_CPU_B;
+ pcibios_write_config_dword(hw->pci_bus, hw->pci_dev_func,
+ PCI_INT_CONFIG, ut_u32);
+#endif
printk(KERN_INFO "%s: IRQ %d allocated to the S514 card\n",
modname, hw->irq);
@@ -1961,7 +2134,7 @@
(unsigned long)16);
if(!hw->dpmbase || !hw->vector) {
- printk(KERN_ERR "%s: PCI virtual memory allocation failed\n",
+ printk(KERN_INFO "%s: PCI virtual memory allocation failed\n",
modname);
return 0;
}
@@ -1983,49 +2156,99 @@
char S514_found_in_slot = 0;
u16 PCI_subsys_vendor;
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
struct pci_dev *pci_dev = NULL;
+#else
+ int pci_index;
+#endif
slot_no = hw->S514_slot_no;
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
while ((pci_dev = pci_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_dev))
!= NULL) {
- if (pci_enable_device(pci_dev))
- continue;
- PCI_subsys_vendor = pci_dev->subsystem_vendor;
- if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR)
+
+ pci_read_config_word(pci_dev, PCI_SUBSYS_VENDOR_WORD,
+ &PCI_subsys_vendor);
+
+ if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR)
continue;
- hw->pci_dev = pci_dev;
+
+ hw->pci_dev = pci_dev;
+
if(find_first_S514_card)
return(1);
+
number_S514_cards ++;
- printk(KERN_INFO
+
+ printk(KERN_INFO
"%s: S514 card found, slot #%d (devfn 0x%X)\n",
modname, ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK),
pci_dev->devfn);
- if(slot_no && (((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK) ==
- slot_no)) {
+
+ if (hw->auto_pci_cfg){
+ hw->S514_slot_no = ((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK);
+ slot_no = hw->S514_slot_no;
+
+ }else if (((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK) == slot_no){
+ S514_found_in_slot = 1;
+ break;
+ }
+ }
+
+#else
+ //LINUX VERSION 2.0.X
+ for (pci_index = 0; pci_index < MAX_S514_CARDS; pci_index ++) {
+ if (pcibios_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_index,
+ &hw->pci_bus, &hw->pci_dev_func)!=PCIBIOS_SUCCESSFUL) {
+ break;
+ }
+
+ pcibios_read_config_word(hw->pci_bus, hw->pci_dev_func,
+ PCI_SUBSYS_VENDOR_WORD, &PCI_subsys_vendor);
+
+ if (PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR)
+ continue;
+
+ if (find_first_S514_card)
+ return(1);
+
+ number_S514_cards ++;
+
+ printk(KERN_INFO "%s: S514 card found, bus #%d, slot #%d\n",
+ modname, hw->pci_bus,
+ ((hw->pci_dev_func >> 3) & PCI_DEV_SLOT_MASK));
+
+ if (hw->auto_pci_cfg){
+ hw->S514_slot_no = ((hw->pci_dev_func >> 3) & PCI_DEV_SLOT_MASK)
+ slot_no = hw->S514_slot_no;
+
+ }else if (((hw->pci_dev_func >> 3) & PCI_DEV_SLOT_MASK) == slot_no) {
S514_found_in_slot = 1;
break;
}
}
+#endif
/* if no S514 adapter has been found, then exit */
- if(!number_S514_cards) {
- printk(KERN_ERR "%s: no S514 adapters found\n", modname);
+ if (!number_S514_cards) {
+ printk(KERN_INFO "%s: Error, no S514 adapters found\n", modname);
return 0;
}
/* if more than one S514 card has been found, then the user must have */ /* defined a slot number so that the correct adapter is used */
- else if((number_S514_cards > 1) && !slot_no) {
- printk(KERN_ERR "%s: More than one S514 adapter found\n",
- modname);
- printk(KERN_ERR "Define a PCI slot number for this adapter\n");
+ else if ((number_S514_cards > 1) && hw->auto_pci_cfg) {
+ printk(KERN_INFO "%s: Error, PCI Slot autodetect Failed! \n"
+ "%s: More than one S514 adapter found.\n"
+ "%s: Disable the Autodetect feature and supply\n"
+ "%s: the PCISLOT numbers for each card.\n",
+ modname,modname,modname,modname);
return 0;
}
/* if the user has specified a slot number and the S514 adapter has */
/* not been found in that slot, then exit */
- else if (slot_no && !S514_found_in_slot) {
- printk(KERN_ERR
- "%s: S514 card not found in specified slot #%d\n",
+ else if (!hw->auto_pci_cfg && !S514_found_in_slot) {
+ printk(KERN_INFO
+ "%s: Error, S514 card not found in specified slot #%d\n",
modname, slot_no);
return 0;
}
@@ -2138,5 +2361,170 @@
return crc;
}
+static int init_pci_slot(sdlahw_t *hw)
+{
+
+ u32 int_status;
+ int volatile found=0;
+ int i=0;
+
+ /* Check if this is a very first load for a specific
+ * pci card. If it is, clear the interrput bits, and
+ * set the flag indicating that this card was initialized.
+ */
+
+ for (i=0; (i<MAX_S514_CARDS) && !found; i++){
+ if (pci_slot_ar[i] == hw->S514_slot_no){
+ found=1;
+ break;
+ }
+ if (pci_slot_ar[i] == 0xFF){
+ break;
+ }
+ }
+
+ if (!found){
+ read_S514_int_stat(hw,&int_status);
+ S514_intack(hw,int_status);
+ if (i == MAX_S514_CARDS){
+ printk(KERN_INFO "%s: Critical Error !!!\n",modname);
+ printk(KERN_INFO
+ "%s: Number of Sangoma PCI cards exceeded maximum limit.\n",
+ modname);
+ printk(KERN_INFO "Please contact Sangoma Technologies\n");
+ return 1;
+ }
+ pci_slot_ar[i] = hw->S514_slot_no;
+ }
+ return 0;
+}
+
+static int pci_probe(sdlahw_t *hw)
+{
+
+ unsigned char slot_no;
+ int number_S514_cards = 0;
+ u16 PCI_subsys_vendor;
+ u16 PCI_card_type;
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+ struct pci_dev *pci_dev = NULL;
+ struct pci_bus *bus = NULL;
+#else
+ int pci_index;
+ u8 irq;
+#endif
+
+ slot_no = 0;
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+ while ((pci_dev = pci_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_dev))
+ != NULL) {
+
+ pci_read_config_word(pci_dev, PCI_SUBSYS_VENDOR_WORD,
+ &PCI_subsys_vendor);
+
+ if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR)
+ continue;
+
+ pci_read_config_word(pci_dev, PCI_CARD_TYPE,
+ &PCI_card_type);
+
+ bus = pci_dev->bus;
+
+ /* A dual cpu card can support up to 4 physical connections,
+ * where a single cpu card can support up to 2 physical
+ * connections. The FT1 card can only support a single
+ * connection, however we cannot distinguish between a Single
+ * CPU card and an FT1 card. */
+ if (PCI_card_type == S514_DUAL_CPU){
+ number_S514_cards += 4;
+ printk(KERN_INFO
+ "wanpipe: S514-PCI card found, cpu(s) 2, bus #%d, slot #%d, irq #%d\n",
+ bus->number,((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK),
+ pci_dev->irq);
+ }else{
+ number_S514_cards += 2;
+ printk(KERN_INFO
+ "wanpipe: S514-PCI card found, cpu(s) 1, bus #%d, slot #%d, irq #%d\n",
+ bus->number,((pci_dev->devfn >> 3) & PCI_DEV_SLOT_MASK),
+ pci_dev->irq);
+ }
+ }
+
+#else
+ for (pci_index = 0; pci_index < MAX_S514_CARDS; pci_index ++) {
+
+ if(pcibios_find_device(V3_VENDOR_ID, V3_DEVICE_ID, pci_index,
+ &hw->pci_bus, &hw->pci_dev_func)!=PCIBIOS_SUCCESSFUL) {
+ break;
+ }
+ pcibios_read_config_word(hw->pci_bus, hw->pci_dev_func,
+ PCI_SUBSYS_VENDOR_WORD, &PCI_subsys_vendor);
+ if(PCI_subsys_vendor != SANGOMA_SUBSYS_VENDOR)
+ continue;
+
+ pcibios_read_config_word(hw->pci_bus,hw->pci_dev_func,PCI_CARD_TYPE,
+ &PCI_card_type);
+
+ pcibios_read_config_byte(hw->pci_bus, hw->pci_dev_func,
+ PCI_INT_LINE_BYTE, &irq);
+
+ /* A dual cpu card can support up to 4 physical connections,
+ * where a single cpu card can support up to 2 physical
+ * connections. The FT1 card can only support a single
+ * connection, however we cannot distinguish between a Single
+ * CPU card and an FT1 card. */
+ if (PCI_card_type == S514_DUAL_CPU){
+ number_S514_cards += 4;
+ printk(KERN_INFO "%s: S514-PCI card found, cpu(s) 2, bus #%d, slot #%d, irq #%d\n",
+ modname, hw->pci_bus,
+ ((hw->pci_dev_func >> 3) & PCI_DEV_SLOT_MASK),irq);
+ }else{
+ printk(KERN_INFO "%s: S514-PCI card found, cpu(s) 1, bus #%d, slot #%d, irq #%d\n",
+ modname, hw->pci_bus,
+ ((hw->pci_dev_func >> 3) & PCI_DEV_SLOT_MASK),irq);
+ number_S514_cards += 2;
+ }
+ }
+#endif
+
+ return number_S514_cards;
+
+}
+
+
+
+#if defined(LINUX_2_1) || defined(LINUX_2_4)
+EXPORT_SYMBOL(wanpipe_hw_probe);
+#endif
+
+unsigned wanpipe_hw_probe(void)
+{
+ sdlahw_t hw;
+ unsigned* opt = s508_port_options;
+ unsigned cardno=0;
+ int i;
+
+ memset(&hw, 0, sizeof(hw));
+
+ for (i = 1; i <= opt[0]; i++) {
+ if (detect_s508(opt[i])){
+ /* S508 card can support up to two physical links */
+ cardno+=2;
+ printk(KERN_INFO "wanpipe: S508-ISA card found, port 0x%x\n",opt[i]);
+ }
+ }
+
+ #ifdef CONFIG_PCI
+ hw.S514_slot_no = 0;
+ cardno += pci_probe(&hw);
+ #else
+ printk(KERN_INFO "wanpipe: Warning, Kernel not compiled for PCI support!\n");
+ printk(KERN_INFO "wanpipe: PCI Hardware Probe Failed!\n");
+ #endif
+
+ return cardno;
+}
/****** End *****************************************************************/
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)