/**************************************************************************************** * dda_arnit_close.c * Linux atm module implementation. * * 2003 (c) Texas Instruments Inc. * * 8/15/2006 MK CQ10844: Changed avsar_ver proc entry to include display of DSLDK * version in addition to all other version information. * 8/15/2006 MK CQ10841: Fixed kernel panic issue in reboot test caused by improper * shutdown of channel when multiple channels are present. * 8/15/2006 Mk CQ10847: Fixed available_tx_bufs allocation for all channels. * 9/22/2006 AV Protecting the multiple calls to channel close. * 9/26/2006 AV Making changes in the ddc_atm_init to pass in the Rx and Tx Queues to * use for the OAM channel. * 10/8/2006 AV Enabling the interrupt pacing for UR8. * 10/9/2006 AV Adding Tasklet mode support for Tx and Rx. * 10/19/2006 EP Adding free_pages for the DSP image when we do rmmod. * 10/25/2006 AV Changing the channel close to use a semaphore intead of a spin_lock, * as the channel close DDC function puts the task to sleep. * 10/31/2006 AV Consolidated the calls for the DDC_sar_handle_tx_process() and DDC_sar_handle_rx_process(). * 12/01/06 CPH/MK Added correct UR8 QoS priority setting in DDA_atm_open(). * 12/15/06 MK CQ11264: Made the change in led_func() due the change in outVal() API in base PSP. * Made the change in DDA_Led_func() for appropriately turning LED ON/OFF * 1/29/2007 CZ CQ11294: fix Unloading DSL driver module. This fix is temporary. We should revist * the change here after OAM channel is fully functional. * 02/14/2007 EP Clean up psp trace. ****************************************************************************************/ #include "dda_ti_dsl.h" #include "dda_input.h" /* Sysctl */ static void DDA_dsl_dslmod_sysctl_register(void); static void DDA_dsl_dslmod_sysctl_unregister(void); static int DDA_atm_get_ESI (struct atm_dev *dev); static int DDA_atm_irq_request (Tn7AtmPrivate * priv); static int DDA_atm_open (struct atm_vcc *vcc); static void DDA_atm_close (struct atm_vcc *vcc); static int INIT_USE_ONLY DDA_atm_detect (void); static int INIT_USE_ONLY DDA_atm_register (Tn7AtmPrivate * priv); static int DDA_atm_xlate_proc_name (const char *name, struct proc_dir_entry **ret, const char **residual); static void DDA_dsl_register_dslss_led(Tn7AtmPrivate * priv); //bk DSP FW Location wird als Param übergeben char *firmware_load_file = "/dev/null"; module_param(firmware_load_file, charp, 0); //bk: following params are unused so far, but already implemented for backwards compatibility to AR7 avm_atm driver char *annex = ""; module_param(annex, charp, 0); char *ptest = ""; module_param(ptest, charp, 0); //end bk char info[MAX_STR_SIZE]; ctl_table dslmod_table[] = { {DEV_DSLMOD, "dslmod", info, DSL_MOD_SIZE, 0644, NULL, &dslmod_sysctl} , {0} }; /* Make sure that /proc/sys/dev is there */ ctl_table dslmod_root_table[] = { #ifdef CONFIG_PROC_FS {CTL_DEV, "dev", NULL, 0, 0555, dslmod_table} , #endif /* CONFIG_PROC_FS */ {0} }; static struct ctl_table_header *dslmod_sysctl_header; /* Common LED variables. */ #if defined (CONFIG_MIPS_AVALANCHE_COLORED_LED) || defined (CONFIG_LED_MODULE) //static int led_on; /* Definition of the handle for LED module. They will be NULL for old LED implementation. */ void *hnd_LED_0 = NULL; #endif #if defined (CONFIG_LED_MODULE) led_reg_t ledreg[2]; #endif #if defined (CONFIG_MIPS_AVALANCHE_COLORED_LED) /*since the structure has the same elements as led_reg_t, we are re-using the variable name. */ #ifndef BASE_PSP_8X static struct led_funcs ledreg[2]; #endif #endif Tn7AtmPrivate *Local_priv = NULL; struct atm_dev *mydev; /* Proc */ const char drv_proc_root_folder[] = "avalanche/"; static struct proc_dir_entry *root_proc_dir_entry = NULL; #define DRV_PROC_MODE 0644 static int proc_root_already_exists = TRUE; /* *INDENT-OFF* */ static struct { const unsigned char name[32]; int (*read_func) (char* , char **, off_t , int ,int *, void *); int (*write_func) (struct file *, const char * , unsigned long , void *); } proc_if[] = { {"avsar_ver", DDA_dsldk_proc_version, NULL}, {"avsar_channels", DDA_atm_proc_channels, NULL}, {"avsar_sarhal_stats", DDA_sar_proc_sar_stat, NULL}, {"avsar_oam_ping", DDA_sar_proc_oam_ping, NULL}, {"avsar_pvc_table", DDA_sar_proc_pvc_table, NULL}, {"avsar_rxsnr0", DDA_dsl_proc_snr0, NULL}, {"avsar_rxsnr1", DDA_dsl_proc_snr1, NULL}, {"avsar_rxsnr2", DDA_dsl_proc_snr2, NULL}, {"clear_eoc_stats", DDA_dsl_proc_eoc, NULL}, {"avsar_bit_allocation_table", DDA_dsl_proc_bit_allocation, NULL}, {"avsar_dsl_modulation_schemes",DDA_dsl_proc_train_mode_export, NULL}, #ifndef NO_ADV_STATS {"avsar_SNRpsds", DDA_dsl_proc_SNRpsds, NULL}, {"avsar_QLNpsds", DDA_dsl_proc_QLNpsds, NULL}, #endif {"avsar_private", DDA_atm_proc_private, NULL}, {"avsar_modem_training", DDA_dsl_proc_modem, NULL}, {"avsar_modem_stats", DDA_dsl_proc_stats, DDA_dsl_proc_write_stats}, #ifdef ADV_DIAG_STATS //CQ10275 //for 2.6 {"avsar_modem_adv_stats", DDA_dsl_proc_adv_stats, NULL}, //For 2.4 kernel, due to proc file system size limitation {"avsar_modem_adv_stats1", DDA_dsl_proc_adv_stats1, NULL}, {"avsar_modem_adv_stats2", DDA_dsl_proc_adv_stats2, NULL}, {"avsar_modem_adv_stats3", DDA_dsl_proc_adv_stats3, NULL}, #endif //ADV_DIAG_STATS {"avsar_qos_enable", DDA_atm_proc_qos_read, DDA_atm_proc_qos_write} }; /* *INDENT-ON* */ /* *INDENT-OFF* */ static const struct atmdev_ops DDA_atm_ops = { open: DDA_atm_open, close: DDA_atm_close, ioctl: DDA_atm_ioctl, getsockopt: NULL, setsockopt: NULL, send: DDA_atm_send, phy_put: NULL, phy_get: NULL, change_qos: DDA_atm_change_qos, }; /* *INDENT-ON* */ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * Function: int DDA_atm_probe(void) * * Description: Avalanche SAR driver probe (see net/atm/pvc.c) * this is utilized when the SAR driver is built * into the kernel and needs to be configured. * *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ int INIT_USE_ONLY DDA_atm_probe (void) { return (DDA_atm_detect()); } /************************************************************ NEED FN HEADER ************************************************************/ static int INIT_USE_ONLY DDA_atm_detect (void) { Tn7AtmPrivate *priv; struct proc_dir_entry *dsl_wr_file = NULL; /* Only for ones with a write * function. */ int ctr; const char *residual; dgprintf (4, "DDA_atm_detect().\n"); /* * Device allocated as a global static structure at top of code "mydev" */ /* * Alloc priv struct */ //bk: war bei TI in einem fs_initcall ctr = avalanche_proc_init(); //end bk priv = kmalloc (sizeof (Tn7AtmPrivate), GFP_KERNEL); if (!priv) { printk ("unable to kmalloc priv structure. Killing autoprobe.\n"); return -ENODEV; } memset (priv, 0, sizeof (Tn7AtmPrivate)); priv->name = "TI Avalanche DSL"; priv->proc_name = "avsar"; //AV_26 priv->stats = kmalloc (sizeof (struct net_device_stats), GFP_KERNEL); if (!priv->stats) { printk ("unable to kmalloc priv structure. Killing autoprobe.\n"); return -ENODEV; } memset (priv->stats, 0, sizeof (struct net_device_stats)); if ((DDA_atm_register(priv)) == ATM_REG_FAILED) return -ENODEV; if(!DDA_init_envs()) { printk ("Unable to read user inputs. Killing autoprobe.\n"); return -ENODEV; } /* The OAM queues to use. */ priv->Oam_txq = UR8_DEF_OAM_TXQ; priv->Oam_rxq = UR8_DEF_OAM_RXQ; //AV: Moved to DDC. if (DDC_atm_init (&priv->dslPriv, priv->dev, priv->Oam_txq, priv->Oam_rxq)) { printk ("Error : Failed to Initialize the DSL subsystem !!.\n"); return -ENODEV; } /* This is needed for the Led initialization. */ Local_priv = priv; /* the driver always works in the tasklet mode */ #ifdef TI_DSL_TASKLET_MODE printk("%s: Spawing off the tasklets \n",__FUNCTION__); tasklet_init (&priv->tx_tasklet, cpsar_handle_tx_tasklet, (unsigned long) priv); tasklet_init (&priv->rx_tasklet, cpsar_handle_rx_tasklet, (unsigned long) priv); #endif /* * register dslss LED with led module. This is an empty function if * LEDs are not configured. */ DDA_dsl_register_dslss_led(priv); /* Moved out of DDC_atm_init */ if (DDA_atm_get_ESI (priv->dev) < 0) /* set ESI */ return -ENODEV; if (DDA_atm_irq_request (priv) < 0) return -EBUSY; /* * Set up proc entry for atm stats */ if (DDA_atm_xlate_proc_name(drv_proc_root_folder, &root_proc_dir_entry, &residual)) { printk ("Creating new root folder %s in the proc for the driver stats \n", drv_proc_root_folder); root_proc_dir_entry = proc_mkdir (drv_proc_root_folder, NULL); if (!root_proc_dir_entry) { printk ("Error : Failed to Initialize the proc subsystem !!.\n"); return -ENOMEM; } proc_root_already_exists = FALSE; } /* * AV: Clean-up. Moved all the definitions to the data structure. */ for (ctr = 0; ctr < (NUM_ELEMS (proc_if)); ctr++) { /* Only if we have a write function, we create a normal proc file. */ if(proc_if[ctr].write_func) { dsl_wr_file = create_proc_entry (proc_if[ctr].name, DRV_PROC_MODE, root_proc_dir_entry); if (dsl_wr_file) { dsl_wr_file->read_proc = proc_if[ctr].read_func; dsl_wr_file->write_proc = proc_if[ctr].write_func; dsl_wr_file->data = (void *)priv; } dsl_wr_file = NULL; } else { /* Create a read-only entry. */ create_proc_read_entry (proc_if[ctr].name, 0, root_proc_dir_entry, proc_if[ctr].read_func, priv); } } DDA_dsl_dslmod_sysctl_register(); printk ("Texas Instruments ATM driver: version:[%d.%02d.%02d.%02d]\n", LINUXATM_VERSION_MAJOR, LINUXATM_VERSION_MINOR, LINUXATM_VERSION_BUGFIX, LINUXATM_VERSION_BUILDNUM); return 0; } /************************************************************ NEED FN HEADER ************************************************************/ #ifdef UR8_SAR static unsigned int tx_cnt = 0; irqreturn_t DDA_atm_sar_tx_irq (int irq, void *voiddev, struct pt_regs *regs) { struct atm_dev *atmdev; Tn7AtmPrivate *priv; #ifndef TI_DSL_TASKLET_MODE int retval; int more; #endif //printk("[bk] %s: SAR Tx Interrupt!\n", __FUNCTION__); dgprintf (6, "DDA_atm_sar_irq\n"); #ifdef TIATM_INST_SUPP psp_trace (ATM_DRV_SAR_ISR_ENTER); #endif atmdev = (struct atm_dev *) voiddev; priv = (Tn7AtmPrivate *) atmdev->dev_data; tx_cnt++; #ifdef TI_DSL_TASKLET_MODE tasklet_schedule (&priv->tx_tasklet); #else retval = DDC_sar_handle_tx_process (priv->dslPriv, irq, &more); #endif #ifdef TIATM_INST_SUPP psp_trace_par (ATM_DRV_SAR_ISR_EXIT, 0); #endif return IRQ_HANDLED; } #endif /* UR8_SAR */ /************************************************************ NEED FN HEADER ************************************************************/ #ifdef UR8_SAR static unsigned int rx_cnt = 0; irqreturn_t DDA_atm_sar_rx_irq (int irq, void *voiddev, struct pt_regs *regs) { struct atm_dev *atmdev; Tn7AtmPrivate *priv; #ifndef TI_DSL_TASKLET_MODE int more; int retval; #endif //printk("[bk] %s: SAR Rx Interrupt!\n", __FUNCTION__); dgprintf (6, "DDA_atm_sar_irq\n"); #ifdef TIATM_INST_SUPP psp_trace (ATM_DRV_SAR_ISR_ENTER); #endif atmdev = (struct atm_dev *) voiddev; priv = (Tn7AtmPrivate *) atmdev->dev_data; rx_cnt++; #ifdef TI_DSL_TASKLET_MODE tasklet_schedule (&priv->rx_tasklet); #else retval = DDC_sar_handle_rx_process (priv->dslPriv, irq, &more); #endif dgprintf (6, "Leaving DDA_atm_sar_irq\n"); #ifdef TIATM_INST_SUPP psp_trace_par (ATM_DRV_SAR_ISR_EXIT, 0); #endif return IRQ_HANDLED; } #endif /* UR8_SAR */ /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * Function: int DDA_atm_irq_request(struct atm_dev *dev) * * Description: Initialize Interrupt handler * *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ static int DDA_atm_irq_request (Tn7AtmPrivate * priv) { struct atm_dev *dev = priv->dev; dgprintf (3, "DDA_atm_irq_request() entered \n"); /* * Register SAR interrupt */ //AV_DDM: This needs to be a function from the DDC. #ifdef AR7_SAR priv->sar_irq = LNXINTNUM (ATM_SAR_INT); /* Interrupt line # */ if (request_irq (priv->sar_irq, DDA_atm_sar_irq, SA_INTERRUPT, "SAR ", dev)) { printk ("Could not register DDA_atm_sar_irq\n"); return -1; } #endif #ifdef UR8_SAR //AV_SM : THIS SHOULD BE CHANGED. priv->sar_tx_irq = ATM_SAR_INT_TX_INT; /* Interrupt line #17 */ if (request_irq (LNXINTNUM(priv->sar_tx_irq), DDA_atm_sar_tx_irq, SA_INTERRUPT, "SAR_TX ", dev)) { printk ("Could not register DDA_atm_sar_tx_irq\n"); return -1; } priv->sar_oam_tx_irq = ATM_SAR_INT_TX_INT + 1; /* Interrupt line #18 */ if (request_irq (LNXINTNUM(priv->sar_oam_tx_irq), DDA_atm_sar_tx_irq, SA_INTERRUPT, "SAR_OAM_TX ", dev)) { printk ("Could not register DDA_atm_sar_oam_tx_irq\n"); return -1; } //AV_SM : THIS SHOULD BE CHANGED. priv->sar_rx_irq = ATM_SAR_INT_RX_INT; /* Interrupt line #34 */ if (request_irq (LNXINTNUM(priv->sar_rx_irq), DDA_atm_sar_rx_irq, SA_INTERRUPT, "SAR_RX ", dev)) { printk ("Could not register DDA_atm_sar_rx_irq\n"); return -1; } priv->sar_oam_rx_irq = ATM_SAR_INT_RX_INT + 1; /* Interrupt line #35 */ if (request_irq (LNXINTNUM(priv->sar_oam_rx_irq), DDA_atm_sar_rx_irq, SA_INTERRUPT, "SAR_OAM_RX ", dev)) { printk ("Could not register DDA_atm_sar_oam_rx_irq\n"); return -1; } #endif //AV_DBG printk ("%s: SAR Interrupt registered \n",__FUNCTION__); /* * interrupt pacing */ DDA_get_value_from_offset(sar_ipacemax, &priv->dslPriv->def_sar_inter_pace); #ifdef AR7_SAR avalanche_request_pacing (priv->sar_irq, ATM_SAR_INT_PACING_BLOCK_NUM, priv->dslPriv->def_sar_inter_pace); #endif #ifdef UR8_SAR /* avalanche_request_pacing (LNXINTNUM (ATM_SAR_INT_RX_INT), 2, priv->dslPriv->def_sar_inter_pace); avalanche_request_pacing (LNXINTNUM (ATM_SAR_INT_TX_INT), 3, priv->dslPriv->def_sar_inter_pace); //AV_DBG printk ("%s: Pacing registered with %d \n",__FUNCTION__, priv->dslPriv->def_sar_inter_pace);*/ #endif /* * Register Receive interrupt from the DSLSS. */ //AV_DDM: This needs to be a function from the DDC. #ifdef UR8_SAR priv->dsl_irq = LNXINTNUM(28); #else priv->dsl_irq = LNXINTNUM (priv->dslPriv->dsl_int); /* Interrupt line # */ #endif if (request_irq (priv->dsl_irq, DDA_atm_dsl_irq, SA_INTERRUPT, "DSL ", dev)) { printk ("Could not register DDA_atm_dsl_irq\n"); return -1; } //AV_DBG printk ("%s: DSL Interrupt registered \n",__FUNCTION__); /***** VRB Tasklet Mode ****/ #ifdef CPATM_TASKLET_MODE tasklet_init (&DDA_atm_tasklet, DDA_atm_handle_tasklet, (unsigned long) dev); #endif /***************/ return 0; } /************************************************************ NEED FN HEADER ************************************************************/ static void str2eaddr (char *pMac, char *pStr) { char tmp[3]; int i; for (i = 0; i < 6; i++) { tmp[0] = pStr[i * 3]; tmp[1] = pStr[i * 3 + 1]; tmp[2] = 0; pMac[i] = os_atoh (tmp); } } /************************************************************ NEED FN HEADER ************************************************************/ static int DDA_atm_get_ESI (struct atm_dev *dev) { int i; char esi_addr[ESI_LEN] = { 0x00, 0x00, 0x11, 0x22, 0x33, 0x44 }; char *esiaddr_str = NULL; if(!DDA_get_value_from_offset(ATM_ETSI, &esiaddr_str)) { if (!esiaddr_str) { printk("Using default macc address = 00:01:02:03:04:05\n"); esiaddr_str = "00:00:02:03:04:05"; } } str2eaddr (esi_addr, esiaddr_str); for (i = 0; i < ESI_LEN; i++) dev->esi[i] = esi_addr[i]; return 0; } /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * Function: int DDA_atm_registration(struct DDA_* DDA_) * * Description: ATM driver registration * *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ static int INIT_USE_ONLY DDA_atm_register (Tn7AtmPrivate * priv) { /* * allocate memory for the device */ dgprintf (4, "device %s being registered\n", priv->name); mydev = atm_dev_register (priv->proc_name, &DDA_atm_ops, -1, NULL); if (mydev == NULL) { printk ("atm_dev_register returning NULL\n"); return ATM_REG_FAILED; } printk ("registered device %s\n", priv->name); mydev->dev_data = priv; /* setup device data in atm_dev struct */ priv->dev = mydev; /* setup atm_device in avalanche sar struct */ mydev->ci_range.vpi_bits = ATM_CI_MAX; /* atm supports 11 bits */ mydev->ci_range.vci_bits = 16; /* atm VCI max = 16 bits */ return ATM_REG_OK; } /************************************************************ NEED FN HEADER ************************************************************/ #if ((CONFIG_MIPS_AVALANCHE_COLORED_LED) && (BASE_PSP_8X)) static LED_OBJ_HND* led_cb_hndl = NULL; static int led_func(unsigned int p1, unsigned int p2, unsigned int p3) { //DDA_printf("%s: Called with p1 = %d, p2 =%d and p3 =%d \n",__FUNCTION__, p1, p2, p3); if(p1) DDC_dsl_led_on(Local_priv->dslPriv); else DDC_dsl_led_off(Local_priv->dslPriv); return 0; } #endif /************************************************************ NEED FN HEADER ************************************************************/ int DDA_Led_func(int state_id) { #ifdef CONFIG_MIPS_AVALANCHE_COLORED_LED //TN7DSL_LED_ACTION(module_handle, module_name, state_id); //DDA_printf("%s: hnd_LED_0 = %p, state_id = %d\n", __FUNCTION__, hnd_LED_0, state_id); if(led_cb_hndl) return( led_manager_led_action(hnd_LED_0, state_id) ); else #endif return -1; } /************************************************************ NEED FN HEADER ************************************************************/ static void DDA_dsl_register_dslss_led(Tn7AtmPrivate * priv) { //AV_26 //#if 0 #ifdef CONFIG_MIPS_AVALANCHE_COLORED_LED #ifdef BASE_PSP_8X LED_FUNCS_T funcs; DDC_dsl_led_init(priv->dslPriv); /* Register with the new LED module */ hnd_LED_0 = led_manager_register_module("adsl",0); if(!hnd_LED_0) { DDA_printf("ERROR DSL: Unable to register with LED module\n"); return; } // register LED1 output with led module funcs.domain = 1; funcs.pos_map[0] = 1; funcs.pos_map[1] = 0; funcs.off_val[0] = 0; funcs.off_val[1] = 0; funcs.outVal = led_func; led_cb_hndl = led_manager_install_callbacks(&funcs); if(led_cb_hndl < 0) { DDA_printf("ERROR DSL: Unable to register with LED module\n"); ; led_manager_unregister_module(hnd_LED_0); hnd_LED_0 = NULL; } priv->dslPriv->hnd_LED_0 = hnd_LED_0; #endif /* BASE_PSP_8X */ #ifdef BASE_PSP_7X /* Register with the new LED module */ hnd_LED_0 = led_manager_register_module("adsl",0); if(!hnd_LED_0) { DDA_printf("ERROR DSL: Unable to register with LED module\n"); return; } // register LED1 output with led module ledreg[1].led_init = (void *)DDC_dsl_led_init; ledreg[1].led_on = (void *)DDC_dsl_led_on; ledreg[1].led_off = (void *)DDC_dsl_led_off; //ledreg[1].param = 1; ledreg[1].param = (unsigned long) priv->dslPriv; if( led_manager_install_callbacks(hnd_LED_0, LED_NUM_1, &ledreg[1]) < 0) { DDA_printf("ERROR DSL: Unable to register with LED module\n"); ; led_manager_unregister_module(hnd_LED_0); hnd_LED_0 = NULL; } #endif /* BASE_PSP_7X */ #endif /* CONFIG_MIPS_AVALANCHE_COLORED_LED */ //#endif } /************************************************************ NEED FN HEADER ************************************************************/ /* * This function matches a name such as "serial", and that specified by the * proc_dir_entry */ static int DDA_atm_proc_match (int len, const char *name, struct proc_dir_entry *de) { if (!de || !de->low_ino) return 0; if (de->namelen != len) return 0; return !strncmp (name, de->name, len); } /************************************************************ NEED FN HEADER ************************************************************/ /* * This function parses a name such as "tty/driver/serial", and * returns the struct proc_dir_entry for "/proc/tty/driver", and * returns "serial" in residual. */ static int DDA_atm_xlate_proc_name (const char *name, struct proc_dir_entry **ret, const char **residual) { const char *cp = name, *next; struct proc_dir_entry *de; int len; extern struct proc_dir_entry proc_root; de = &proc_root; while (1) { next = strchr (cp, '/'); if (!next) break; len = next - cp; for (de = de->subdir; de; de = de->next) { if (DDA_atm_proc_match (len, cp, de)) break; } if (!de) return -ENOENT; cp += len + 1; } *residual = cp; *ret = de; return 0; } /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * Function: int DDA_atm_exit(void) * * Description: Avalanche SAR exit function * *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ static void DDA_atm_exit (void) { struct atm_dev *dev; Tn7AtmPrivate *priv; int ctr; printk ("DDA_atm_exit()\n"); dev = Local_priv->dev; priv = Local_priv; //Close all open channels. for(ctr = 0; ctr < NUM_ELEMS(priv->dslPriv->lut); ctr++) { //CZ no need to close OAM if((priv->dslPriv->lut[ctr].inuse) && (ctr != RESERVED_OAM_CHANNEL)) DDA_atm_close((struct atm_vcc *)priv->dslPriv->lut[ctr].vcc); } //AV_26 //#if 0 #ifdef CONFIG_LED_MODULE #ifdef DEREGISTER_LED //down(&adsl_sem_overlay); deregister_led_drv(LED_NUM_1); deregister_led_drv(LED_NUM_2); #else led_operation(MOD_ADSL,DEF_ADSL_IDLE); #endif /* DEREGISTER_LED*/ hnd_LED_0 = NULL; #endif /* CONFIG_LED_MODULE */ #ifdef CONFIG_MIPS_AVALANCHE_COLORED_LED led_manager_uninstall_callbacks(led_cb_hndl); led_manager_unregister_module(hnd_LED_0); hnd_LED_0 = NULL; #endif /* CONFIG_MIPS_AVALANCHE_COLORED_LED */ //#endif DDC_dsl_Close(&priv->dslPriv); /* * freeup irq's */ free_irq (priv->dsl_irq, priv->dev); #ifdef AR7_SAR free_irq (priv->sar_irq, priv->dev); #endif #ifdef UR8_SAR free_irq (LNXINTNUM(priv->sar_tx_irq), priv->dev); free_irq (LNXINTNUM(priv->sar_rx_irq), priv->dev); free_irq (LNXINTNUM(priv->sar_oam_tx_irq), priv->dev); free_irq (LNXINTNUM(priv->sar_oam_rx_irq), priv->dev); #ifdef TI_DSL_TASKLET_MODE //AV:TODO kill tasklets tasklet_kill (&priv->tx_tasklet); tasklet_kill (&priv->rx_tasklet); #endif #endif if(!DDA_close_envs()) { printk ("Unable to free user inputs..\n"); } //AV_26 kfree(priv->stats); kfree (dev->dev_data); shutdown_atm_dev(dev); /* * remove proc entries * * AV: Clean-up. Remove all of them from the data structure. */ for (ctr = 0; ctr < (NUM_ELEMS (proc_if)); ctr++) { remove_proc_entry (proc_if[ctr].name, root_proc_dir_entry); } /* * Remove the root folder only if we created it. */ if (!proc_root_already_exists) remove_proc_entry (drv_proc_root_folder, NULL); DDA_dsl_dslmod_sysctl_unregister(); DDA_dsl_DspImageFree(); printk ("AVSAR: Module Removed\n"); } /************************************************************ NEED FN HEADER ************************************************************/ static void DDA_dsl_dslmod_sysctl_register(void) { static int initialized; if (initialized == 1) return; dslmod_sysctl_header = register_sysctl_table(dslmod_root_table, 1); dslmod_root_table->child->de->owner = THIS_MODULE; /* * set the defaults */ info[0] = 0; initialized = 1; } static void DDA_dsl_dslmod_sysctl_unregister(void) { unregister_sysctl_table(dslmod_sysctl_header); } /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * Function: int DDA_atm_open(struct atm_vcc *vcc) * * Description: Device operation: open * *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ //AV_26 //int DDA_atm_open (struct atm_vcc *vcc, short vpi, int vci) static int DDA_atm_open (struct atm_vcc *vcc) { //AV_DDM //DDA_atm_activate_vc_parm_t DDA_atm_activate_vc_parm; DDC_atm_activate_vc_parm_t DDA_atm_activate_vc_parm; int rc; int vpi = vcc->vpi; int vci = vcc->vci; //int flags; //AV_26 //br2684_vcc * foo; //struct atm_dev * dev = vcc->dev; Tn7AtmPrivate *priv = (Tn7AtmPrivate *)vcc->dev->dev_data;; dgprintf(1, "DDA_atm_open()\n"); DDA_atm_activate_vc_parm.priv = priv->dslPriv; if(!priv || !priv->dslPriv) { printk("null priv\n"); return -1; } //AV_26 //MOD_INC_USE_COUNT; //AV_26 /* find a free VPI/VCI */ //DDA_atm_walk_vccs(vcc, &vpi, &vci); //AV_26 //vcc->vpi = vpi; //vcc->vci = vci; if ((vci == ATM_VCI_UNSPEC) || (vpi == ATM_VCI_UNSPEC)) { //AV_26 //MOD_DEC_USE_COUNT; return -EBUSY; } //AV_26 printk("%s: vcc->sk = 0x%p \n", __FUNCTION__, vcc->sk); DDA_atm_activate_vc_parm.vpi = vpi; DDA_atm_activate_vc_parm.vci = vci; if ((vpi == CLEAR_EOC_VPI) && (vci == CLEAR_EOC_VCI)) { /* always use (max_dma_chan+1) for clear eoc */ DDA_atm_activate_vc_parm.chan = EOC_DMA_CHAN; /* check to see whether clear eoc is opened or not */ if (priv->dslPriv->lut[DDA_atm_activate_vc_parm.chan].inuse) { //AV_26 //MOD_DEC_USE_COUNT; printk("DDA_atm_open: Clear EOC channel (dmachan=%d) already in use.\n", DDA_atm_activate_vc_parm.chan); return -EBUSY; } rc = DDC_dsl_clear_eoc_setup(priv->dslPriv); if (rc) { printk("DDA_atm_open: failed to setup clear_eoc\n"); //AV_26 //MOD_DEC_USE_COUNT; return -EBUSY; } DDC_atm_set_lut(priv->dslPriv,vcc, vcc->vpi, vcc->vci, DDA_atm_activate_vc_parm.chan); set_bit(ATM_VF_ADDR, &vcc->flags); /* claim address */ vcc->itf = vcc->dev->number; /* interface number */ } else /* PVC channel setup */ { if ((vpi==REMOTE_MGMT_VPI) && (vci==REMOTE_MGMT_VCI)) { DDA_atm_activate_vc_parm.chan = 14; /* always use chan 14 for MII PVC-base romote mgmt */ } else { rc = DDC_atm_lut_find(priv->dslPriv, vpi, vci); /* check to see whether PVC is opened or not */ if(ATM_NO_DMA_CHAN != rc) { //AV_26 //MOD_DEC_USE_COUNT; printk("PVC already opened. dmachan = %d\n", rc); return -EBUSY; } /*check for available channel */ if((DDA_atm_activate_vc_parm.chan = DDC_atm_walk_lut(priv->dslPriv)) == ATM_NO_DMA_CHAN) { printk("No TX DMA channels available\n"); return -EBUSY; } } set_bit(ATM_VF_ADDR, &vcc->flags); /* claim address */ vcc->itf = vcc->dev->number; /* interface number */ switch(vcc->qos.txtp.traffic_class) { case ATM_CBR: /* Constant Bit Rate */ DDA_atm_activate_vc_parm.qos = 0; DDA_atm_activate_vc_parm.priority = 0; DDA_atm_activate_vc_parm.pcr = vcc->qos.txtp.pcr; DDA_atm_activate_vc_parm.scr = vcc->qos.txtp.pcr; DDA_atm_activate_vc_parm.cdvt = vcc->qos.txtp.max_cdv; break; case ATM_UBR: /* Unspecified Bit Rate */ DDA_atm_activate_vc_parm.qos = 2; DDA_atm_activate_vc_parm.priority = 3; //AV_26 The default values set the PCR to 0 in 2.6. That is bad even for ubr. DDA_atm_activate_vc_parm.mbs = 131072; DDA_atm_activate_vc_parm.pcr = (500 * priv->dslPriv->sar_freq) /*vcc->qos.txtp.pcr*/; DDA_atm_activate_vc_parm.scr = (500 * priv->dslPriv->sar_freq) /*vcc->qos.txtp.scr*/; break; case ATM_VBR: /* Variable Bit Rate-Non RealTime*/ DDA_atm_activate_vc_parm.qos = 1; DDA_atm_activate_vc_parm.priority = 2; DDA_atm_activate_vc_parm.pcr = vcc->qos.txtp.pcr; DDA_atm_activate_vc_parm.scr = vcc->qos.txtp.scr; if(vcc->qos.txtp.max_pcr >= 0) DDA_atm_activate_vc_parm.mbs = vcc->qos.txtp.max_pcr; DDA_atm_activate_vc_parm.cdvt = vcc->qos.txtp.max_cdv; break; // bk add the define ATM_VBR_RT in include/linux/atm.h Check other modifictations of this file in UR8 RGDK case ATM_VBR_RT: /* Variable Bit Rate-RealTime */ DDA_atm_activate_vc_parm.qos = 1; DDA_atm_activate_vc_parm.priority = 1; DDA_atm_activate_vc_parm.pcr = vcc->qos.txtp.pcr; DDA_atm_activate_vc_parm.scr = vcc->qos.txtp.scr; if(vcc->qos.txtp.max_pcr >= 0) DDA_atm_activate_vc_parm.mbs = vcc->qos.txtp.max_pcr; DDA_atm_activate_vc_parm.cdvt = vcc->qos.txtp.max_cdv; break; default: DDA_atm_activate_vc_parm.qos = 2; //UBR DDA_atm_activate_vc_parm.priority = 3; //UBR break; } //spin_lock_irqsave(&chan_init_lock, flags); DDC_atm_set_lut(priv->dslPriv,vcc, vcc->vpi, vcc->vci, DDA_atm_activate_vc_parm.chan); /* These are used for the Input queue throttling. */ DDA_sar_critical_on(); priv->available_tx_bufs[DDA_atm_activate_vc_parm.chan].counter = priv->dslPriv->sarTxBuf; DDA_sar_critical_off(); #if 0 { extern int testflag1; if(testflag1==1) { printk("set pppoa copy on\n"); vcc->qos.txtp.icr=1; } } #endif /* Activate SAR channel */ //spin_lock_irqsave(&chan_init_lock, flags); printk("%s: Opening SAR channel %d \n", __FUNCTION__, DDA_atm_activate_vc_parm.chan); //The following is used in UR8 only DDA_atm_activate_vc_parm.rq_num = 2; DDA_atm_activate_vc_parm.tq_num = 2; rc = DDC_sar_activate_vc(&DDA_atm_activate_vc_parm); if (rc < 0) { printk("failed to activate hw channel\n"); //AV_26 //MOD_DEC_USE_COUNT; DDC_atm_lut_clear(priv->dslPriv, DDA_atm_activate_vc_parm.chan); //spin_unlock_irqrestore(&chan_init_lock, flags); return -EBUSY; } } /* insure that the the vcc struct points to the correct entry in the lookup table */ vcc->dev_data = (void *) &priv->dslPriv->lut[DDA_atm_activate_vc_parm.chan]; //mdelay(100); priv->dslPriv->lut[DDA_atm_activate_vc_parm.chan].ready = 1; clear_bit (ATM_VF_CLOSE, &vcc->flags); /* Closed. */ set_bit(ATM_VF_READY, &vcc->flags); dgprintf (1, "Leave DDA_atm_open\n"); return 0; } static DECLARE_MUTEX(close_sem); /************************************************************ NEED FN HEADER ************************************************************/ static void DDA_atm_close (struct atm_vcc *vcc) { Tn7AtmPrivate *priv; int dmachan; spinlock_t closeLock; unsigned int closeFlag; int rc; priv = (Tn7AtmPrivate *) vcc->dev->dev_data; printk ("%s: closing %d.%d.%d.%d\n", __FUNCTION__, vcc->itf, vcc->vpi, vcc->vci, vcc->qos.aal); spin_lock_irqsave (&closeLock, closeFlag); clear_bit (ATM_VF_READY, &vcc->flags); /* ATM_VF_READY: channel is not * ready to transfer data */ clear_bit (ATM_VF_ADDR, &vcc->flags); /* disclaim address */ set_bit (ATM_VF_CLOSE, &vcc->flags); /* Closed. */ if ((vcc->vpi == CLEAR_EOC_VPI) && (vcc->vci == CLEAR_EOC_VCI)) { dmachan = EOC_DMA_CHAN; } else { dmachan = DDC_atm_lut_find (priv->dslPriv, vcc->vpi, vcc->vci); if (dmachan == ATM_NO_DMA_CHAN) { printk ("Closing channel not found.\n"); spin_unlock_irqrestore (&closeLock, closeFlag); return; } } priv->dslPriv->lut[dmachan].bClosing = 1; priv->dslPriv->lut[dmachan].ready = 0; spin_unlock_irqrestore (&closeLock, closeFlag); if (vcc->vpi == CLEAR_EOC_VPI && vcc->vci == CLEAR_EOC_VCI) { DDC_dsl_clear_eoc_close (priv->dslPriv); } else { /* Proctect multiple calls to channel close, without disabling Interrupts. */ //spin_lock(&closeLock); down(&close_sem); rc = DDC_sar_deactivate_vc (priv->dslPriv, dmachan); //spin_unlock(&closeLock); up(&close_sem); if (rc) /* tear down channel */ { printk ("failed to close channel %d.\n", dmachan); //spin_unlock_irqrestore (&closeLock, closeFlag); //return; } //printk("ChannelTeardown returned rc = %d for chan %d \n", rc, dmachan); //DDA_sar_critical_on(); priv->available_tx_bufs[dmachan].counter = 0; //DDA_sar_critical_off(); } /* * ATM_VF_ADDR: channel is not ready to transfer data */ //spin_lock_irqsave (&closeLock, closeFlag); DDA_sar_critical_on(); DDC_atm_lut_clear (priv->dslPriv, dmachan); DDA_sar_critical_off(); //spin_unlock_irqrestore (&closeLock, closeFlag); //MOD_DEC_USE_COUNT; dgprintf (1, "Leave DDA_atm_close\n"); } //AV_26 MODULE IS NOT REQUIRED //#ifdef MODULE module_init (DDA_atm_detect); module_exit (DDA_atm_exit); //#endif /* MODULE */