From d8365e7fd56ca15c05502848338017013e628a9d Mon Sep 17 00:00:00 2001 From: ppisa Date: Sun, 18 Jan 2004 22:40:32 +0000 Subject: [PATCH 1/1] Rearranged setup to better support cards with irq count differing from chip count. Checked compilation with 2.2.19 kernel. Functionality with 2.2.x not checked. --- lincan/include/can_sysdep.h | 30 +++++ lincan/include/constants.h | 1 + lincan/include/main.h | 4 + lincan/src/can_devrtl.c | 21 +++- lincan/src/kv_pcican.c | 1 + lincan/src/main.c | 19 +++ lincan/src/setup.c | 227 +++++++++++++++++++++++------------- lincan/src/virtual.c | 6 +- 8 files changed, 225 insertions(+), 84 deletions(-) diff --git a/lincan/include/can_sysdep.h b/lincan/include/can_sysdep.h index b719236..5b33971 100644 --- a/lincan/include/can_sysdep.h +++ b/lincan/include/can_sysdep.h @@ -28,8 +28,10 @@ #include /*optional features*/ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)) #define CAN_ENABLE_KERN_FASYNC #define CAN_ENABLE_PCI_SUPPORT +#endif #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) #include @@ -57,6 +59,34 @@ #define DECLARE_MUTEX(name) struct semaphore name=MUTEX #endif /* 2.2.19 */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)) && !defined(DECLARE_TASKLET) + #define tasklet_struct tq_struct + #define DECLARE_TASKLET(_name, _func, _data) \ + struct tq_struct _name = { sync: 0, routine: _func, data: (void*)_data } + + /* void tasklet_init(struct tasklet_struct *t, void (*func)(unsigned long), unsigned long data); */ + #define tasklet_init(_tasklet, _func, _data) \ + do{ \ + /* (_tasklet)->next=NULL; */ \ + /* Above not needed for 2.2.x and buggy for 2.4.x */ \ + (_tasklet)->sync=0; \ + (_tasklet)->routine=_func; \ + (_tasklet)->data=(void*)_data; \ + }while(0) + + /* void tasklet_schedule(struct tasklet_struct *t) */ + #define tasklet_schedule(_tasklet) \ + do{ \ + queue_task(_tasklet,&tq_immediate); \ + mark_bh(IMMEDIATE_BH); \ + }while(0) + + /* void tasklet_kill(struct tasklet_struct *t); */ + #define tasklet_kill(_tasklet) \ + synchronize_irq() + +#endif /* 2.4.0 */ + #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,7)) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) diff --git a/lincan/include/constants.h b/lincan/include/constants.h index df2909f..87863e8 100644 --- a/lincan/include/constants.h +++ b/lincan/include/constants.h @@ -65,6 +65,7 @@ #define CHIP_CONFIGURED (1<<0) #define CHIP_SEGMENTED (1<<1) #define CHIP_IRQ_SETUP (1<<2) +#define CHIP_IRQ_PCI (1<<3) /* These flags can be used for the candevices_t structure flags data entry */ #define CANDEV_PROGRAMMABLE_IRQ (1<<0) diff --git a/lincan/include/main.h b/lincan/include/main.h index f73e967..b4a0b32 100644 --- a/lincan/include/main.h +++ b/lincan/include/main.h @@ -404,3 +404,7 @@ struct boardtype_t { }; const struct boardtype_t* boardtype_find(const char *str); + +#ifdef CAN_WITH_RTL +extern int can_rtl_priority; +#endif /*CAN_WITH_RTL*/ diff --git a/lincan/src/can_devrtl.c b/lincan/src/can_devrtl.c index 182eb42..812ea84 100644 --- a/lincan/src/can_devrtl.c +++ b/lincan/src/can_devrtl.c @@ -22,6 +22,7 @@ unsigned int can_rtl_isr( unsigned int irq_num, struct pt_regs *r ) struct candevice_t *candev; int board_nr; int chip_nr; + int irq2linux=0; pthread_t thread=NULL; DEBUGMSG("can_rtl_isr invoked for irq %d\n",irq_num); @@ -37,14 +38,16 @@ unsigned int can_rtl_isr( unsigned int irq_num, struct pt_regs *r ) set_bit(MSGOBJ_IRQ_REQUEST_b,&chip->pend_flags); set_bit(MSGOBJ_WORKER_WAKE_b,&chip->pend_flags); - + if(chip->flags & CHIP_IRQ_PCI) + irq2linux=1; if(!chip->worker_thread) continue; thread=chip->worker_thread; pthread_kill(thread,RTL_SIGNAL_WAKEUP); } } - /*rtl_global_pend_irq(irq_num);*/ + if(irq2linux) + rtl_global_pend_irq(irq_num); /*if(thread) rtl_reschedule_thread(thread);*/ @@ -134,9 +137,21 @@ void * can_chip_worker_thread(void *arg) int can_chip_setup_irq(struct chip_t *chip) { int ret; + struct sched_param sched_param; + pthread_attr_t attrib; + pthread_attr_t *attrib_p=NULL; if(chip==NULL) return -1; + + if(can_rtl_priority>=0){ + pthread_attr_init(&attrib); + sched_param.sched_priority = can_rtl_priority; + pthread_attr_setschedparam(&attrib, &sched_param); + /* pthread_attr_setschedpolicy(&attrib, SCHED_FIFO); */ + attrib_p=&attrib; + } + if(chip->chipspecops->irq_handler){ if (rtl_request_irq(chip->chip_irq,can_rtl_isr)) return -1; @@ -145,7 +160,7 @@ int can_chip_setup_irq(struct chip_t *chip) chip->flags |= CHIP_IRQ_SETUP; } } - ret=pthread_create(&chip->worker_thread, NULL, can_chip_worker_thread, chip); + ret=pthread_create(&chip->worker_thread, attrib_p, can_chip_worker_thread, chip); if(ret<0) chip->worker_thread=NULL; return ret; diff --git a/lincan/src/kv_pcican.c b/lincan/src/kv_pcican.c index eace091..c49a3de 100644 --- a/lincan/src/kv_pcican.c +++ b/lincan/src/kv_pcican.c @@ -241,6 +241,7 @@ int kv_pcican_init_chip_data(struct candevice_t *candev, int chipnr) candev->chip[chipnr]->sja_cdr_reg = CDR_CBP | CDR_CLK_OFF; candev->chip[chipnr]->sja_ocr_reg = KV_PCICAN_OCR_DEFAULT_STD; candev->chip[chipnr]->clock = 16000000; + candev->chip[chipnr]->flags |= CHIP_IRQ_PCI; return 0; } diff --git a/lincan/src/main.c b/lincan/src/main.c index 817d678..f4edb79 100644 --- a/lincan/src/main.c +++ b/lincan/src/main.c @@ -68,29 +68,48 @@ can_spinlock_t canuser_manipulation_lock; /* Module parameters, some must be supplied at module loading time */ int major=CAN_MAJOR; MODULE_PARM(major,"1i"); +MODULE_PARM_DESC(major,"can be used to change default major [" __MODULE_STRING(CAN_MAJOR) "]"); int minor[MAX_TOT_CHIPS]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; /*MODULE_PARM(minor, "1-" __MODULE_STRING(MAX_TOT_CHIPS)"i");*/ MODULE_PARM(minor, "1-" __MODULE_STRING(MAX_TOT_CHIPS_STR)"i"); +MODULE_PARM_DESC(minor,"can be used to change default starting minor for each channel"); int extended=0; MODULE_PARM(extended,"1i"); +MODULE_PARM_DESC(extended,"enables automatic switching to extended format if ID>2047," + " selects extended frames reception for i82527"); int pelican=0; MODULE_PARM(pelican,"1i"); +MODULE_PARM_DESC(pelican,"unused parameter, PeliCAN used by default for sja1000p chips"); int baudrate[MAX_TOT_CHIPS]; MODULE_PARM(baudrate, "1-" __MODULE_STRING(MAX_TOT_CHIPS_STR)"i"); +MODULE_PARM_DESC(baudrate,"baudrate for each channel in step of 1kHz"); char *hw[MAX_HW_CARDS]={NULL,}; MODULE_PARM(hw, "1-" __MODULE_STRING(MAX_HW_CARDS)"s"); +MODULE_PARM_DESC(hw,"list of boards types to initialize - virtual,pip5,..."); int irq[MAX_IRQ]={-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}; MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_IRQ)"i"); +MODULE_PARM_DESC(irq,"list of iterrupt signal numbers, most ISA has one per chip, no value for PCI or virtual"); unsigned long io[MAX_HW_CARDS]={-1,-1,-1,-1,-1,-1,-1,-1}; MODULE_PARM(io, "1-" __MODULE_STRING(MAX_HW_CARDS)"i"); +MODULE_PARM_DESC(io,"IO address for each board, use 0 for PCI or virtual"); int stdmask=0; MODULE_PARM(stdmask, "1i"); +MODULE_PARM_DESC(stdmask,"default standard mask for i82527 chips"); int extmask=0; MODULE_PARM(extmask, "1i"); +MODULE_PARM_DESC(extmask,"default extended mask for i82527 chips"); int mo15mask=0; MODULE_PARM(mo15mask, "1i"); +MODULE_PARM_DESC(mo15mask,"mask for communication object 15 of i82527 chips"); int processlocal=0; MODULE_PARM(processlocal, "1i"); +MODULE_PARM_DESC(processlocal,"select postprocessing/loopback of transmitted messages - " + "0 .. disabled, 1 .. can be enabled by FIFO filter, 2 .. enabled by default"); +#ifdef CAN_WITH_RTL +int can_rtl_priority=-1; +MODULE_PARM(can_rtl_priority, "1i"); +MODULE_PARM_DESC(can_rtl_priority,"select priority of chip worker thread"); +#endif /*CAN_WITH_RTL*/ /* Other module attributes */ #ifdef MODULE_SUPPORTED_DEVICE diff --git a/lincan/src/setup.c b/lincan/src/setup.c index acc7cac..72ef1a9 100644 --- a/lincan/src/setup.c +++ b/lincan/src/setup.c @@ -18,10 +18,10 @@ extern int sja1000_register(struct chipspecops_t *chipspecops); extern int sja1000p_register(struct chipspecops_t *chipspecops); extern int i82527_register(struct chipspecops_t *chipspecops); -int init_device_struct(int card); -int init_hwspecops(struct candevice_t *candev); -int init_chip_struct(struct candevice_t *candev); -int init_obj_struct(struct candevice_t *candev, struct chip_t *hostchip, int minorbase); +int init_hwspecops(struct candevice_t *candev, int *irqnum_p); +int init_device_struct(int card, int *chan_param_idx_p, int *irq_param_idx_p); +int init_chip_struct(struct candevice_t *candev, int chipnr, int irq, long baudrate); +int init_obj_struct(struct candevice_t *candev, struct chip_t *hostchip, int objnr); int init_chipspecops(struct candevice_t *candev, int chipnr); void *can_checked_malloc(size_t size) @@ -153,16 +153,64 @@ int can_base_addr_fixup(struct candevice_t *candev, unsigned long new_base) return 0; } + +int register_obj_struct(struct msgobj_t *obj, int minorbase) +{ + static int next_minor=0; + int i; + + if(minorbase>=0) + next_minor=minorbase; + if(next_minor>=MAX_TOT_MSGOBJS) + next_minor=0; + i=next_minor; + do{ + if(objects_p[i]==NULL){ + objects_p[i]=obj; + obj->minor=i; + next_minor=i+1; + return 0; + } + if(++i >= MAX_TOT_MSGOBJS) i=0; + }while(i!=next_minor); + obj->minor=-1; + return -1; +} + + +int register_chip_struct(struct chip_t *chip, int minorbase) +{ + static int next_chip_slot=0; + int i; + + if(next_chip_slot>=MAX_TOT_CHIPS) + next_chip_slot=0; + i=next_chip_slot; + do{ + if(chips_p[i]==NULL){ + chips_p[i]=chip; + + next_chip_slot=i+1; + return 0; + } + if(++i >= MAX_TOT_CHIPS) i=0; + }while(i!=next_chip_slot); + return -1; +} + + /* The function init_hw_struct is used to initialize the hardware structure. */ int init_hw_struct(void) { int i=0; + int irq_param_idx=0; + int chan_param_idx=0; hardware_p->nr_boards=0; while ( (hw[i] != NULL) & (i < MAX_HW_CARDS) ) { hardware_p->nr_boards++; - if (init_device_struct(i)) { + if (init_device_struct(i, &chan_param_idx, &irq_param_idx)) { CANMSG("Error initializing candevice_t structures.\n"); return -ENODEV; } @@ -175,10 +223,14 @@ int init_hw_struct(void) /* The function init_device_struct is used to initialize a single device * structure. */ -int init_device_struct(int card) +int init_device_struct(int card, int *chan_param_idx_p, int *irq_param_idx_p) { struct candevice_t *candev; int ret; + int irqnum; + int chipnr; + long bd; + int irqsig=-1; candev=(struct candevice_t *)can_checked_malloc(sizeof(struct candevice_t)); if (candev==NULL) @@ -201,14 +253,42 @@ int init_device_struct(int card) memset(candev->hwspecops, 0, sizeof(struct hwspecops_t)); - if (init_hwspecops(candev)) + if (init_hwspecops(candev, &irqnum)) goto error_nodev; if (candev->hwspecops->init_hw_data(candev)) goto error_nodev; - if ((ret=init_chip_struct(candev))) - goto error_chip; + /* Alocate and initialize the chip structures */ + for (chipnr=0; chipnr < candev->nr_all_chips; chipnr++) { + + if(chipnrnr_all_chips; chipnr++) { + int m=minor[*chan_param_idx_p+chipnr]; + struct chip_t *chip=candev->chip[chipnr]; + int objnr; + + register_chip_struct(chip, m); + + for (objnr=0; objnrmax_objects; objnr++) { + register_obj_struct(chip->msgobj[objnr], m); + if(m>=0) m++; + } + } + + *irq_param_idx_p += irqnum; + *chan_param_idx_p += candev->nr_all_chips; return 0; @@ -231,96 +311,84 @@ int init_device_struct(int card) /* The function init_chip_struct is used to initialize all chip_t structures * on one hardware board. */ -int init_chip_struct(struct candevice_t *candev) +int init_chip_struct(struct candevice_t *candev, int chipnr, int irq, long baudrate) { struct chip_t *chip; - static int irq_count=0; - int i=0; + int objnr; + int ret; - /* Alocate and initialize the chip structures */ - for (i=0; i < candev->nr_all_chips; i++) { - candev->chip[i]=(struct chip_t *)can_checked_malloc(sizeof(struct chip_t)); - if ((chip=candev->chip[i])==NULL) - return -ENOMEM; + candev->chip[chipnr]=(struct chip_t *)can_checked_malloc(sizeof(struct chip_t)); + if ((chip=candev->chip[chipnr])==NULL) + return -ENOMEM; - memset(chip, 0, sizeof(struct chip_t)); - - chip->write_register=candev->hwspecops->write_register; - chip->read_register=candev->hwspecops->read_register; + memset(chip, 0, sizeof(struct chip_t)); - chip->chipspecops=can_checked_malloc(sizeof(struct chipspecops_t)); - if (chip->chipspecops==NULL) - return -ENOMEM; - - chips_p[irq_count]=chip; - chip->chip_idx=i; - chip->hostdevice=candev; - chip->chip_irq=irq[irq_count]; - chip->baudrate=baudrate[irq_count]*1000; - if(!chip->baudrate) - chip->baudrate=baudrate[0]*1000; - chip->flags=0x0; - - candev->hwspecops->init_chip_data(candev,i); - - if (init_chipspecops(candev,i)) - return -ENODEV; - - init_obj_struct(candev, chip, minor[irq_count]); + chip->write_register=candev->hwspecops->write_register; + chip->read_register=candev->hwspecops->read_register; - irq_count++; - } + chip->chipspecops=can_checked_malloc(sizeof(struct chipspecops_t)); + if (chip->chipspecops==NULL) + return -ENOMEM; + + chip->chip_idx=chipnr; + chip->hostdevice=candev; + chip->chip_irq=irq; + chip->baudrate=baudrate; + chip->flags=0x0; + + candev->hwspecops->init_chip_data(candev,chipnr); + + if (init_chipspecops(candev,chipnr)) + return -ENODEV; + + for (objnr=0; objnrmax_objects; objnr++) { + ret=init_obj_struct(candev, chip, objnr); + if(ret<0) return ret; + } return 0; } -int init_obj_struct(struct candevice_t *candev, struct chip_t *hostchip, int minorbase) + +int init_obj_struct(struct candevice_t *candev, struct chip_t *hostchip, int objnr) { struct canque_ends_t *qends; - static int obj_count=0; - int i,max_objects; struct msgobj_t *obj; + int ret; - max_objects=hostchip->max_objects; - for (i=0; imsgobj[i]=obj; - if (obj == NULL) - return -ENOMEM; - - memset(obj, 0, sizeof(struct msgobj_t)); + obj=(struct msgobj_t *)can_checked_malloc(sizeof(struct msgobj_t)); + hostchip->msgobj[objnr]=obj; + if (obj == NULL) + return -ENOMEM; - atomic_set(&obj->obj_used,0); - INIT_LIST_HEAD(&obj->obj_users); - init_timer(&obj->tx_timeout); - - qends = (struct canque_ends_t *)can_checked_malloc(sizeof(struct canque_ends_t)); - if(qends == NULL) return -ENOMEM; - memset(qends, 0, sizeof(struct canque_ends_t)); - obj->hostchip=hostchip; - obj->object=i+1; - obj->qends=qends; - obj->tx_qedge=NULL; - obj->tx_slot=NULL; - obj->obj_flags = 0x0; - - canqueue_ends_init_chip(qends, hostchip, obj); - - if (minorbase == -1) minorbase=obj_count; - if ((minorbase >= 0) && (minorbase+iminor=minorbase+i; - } else obj->minor=-1; + memset(obj, 0, sizeof(struct msgobj_t)); + obj->minor=-1; - candev->hwspecops->init_obj_data(hostchip,i); + atomic_set(&obj->obj_used,0); + INIT_LIST_HEAD(&obj->obj_users); + init_timer(&obj->tx_timeout); - obj_count++; - } + qends = (struct canque_ends_t *)can_checked_malloc(sizeof(struct canque_ends_t)); + if(qends == NULL) return -ENOMEM; + memset(qends, 0, sizeof(struct canque_ends_t)); + obj->hostchip=hostchip; + obj->object=objnr+1; + obj->qends=qends; + obj->tx_qedge=NULL; + obj->tx_slot=NULL; + obj->obj_flags = 0x0; + + ret=canqueue_ends_init_chip(qends, hostchip, obj); + if(ret<0) return ret; + + ret=candev->hwspecops->init_obj_data(hostchip,objnr); + if(ret<0) return ret; + return 0; } -int init_hwspecops(struct candevice_t *candev) +int init_hwspecops(struct candevice_t *candev, int *irqnum_p) { const struct boardtype_t *brp; @@ -331,11 +399,14 @@ int init_hwspecops(struct candevice_t *candev) return -EINVAL; } + if(irqnum_p) + *irqnum_p=brp->irqnum; brp->board_register(candev->hwspecops); return 0; } + int init_chipspecops(struct candevice_t *candev, int chipnr) { if (!strcmp(candev->chip[chipnr]->chip_type,"i82527")) { diff --git a/lincan/src/virtual.c b/lincan/src/virtual.c index 80ce0fb..d8818ab 100644 --- a/lincan/src/virtual.c +++ b/lincan/src/virtual.c @@ -302,7 +302,7 @@ void virtual_schedule_next(struct msgobj_t *obj) if(cmd>=0) { mod_timer(&obj->tx_timeout, jiffies+virtual_bus_latency(obj)); - CANMSG("virtual: scheduled delivery\n"); + DEBUGMSG("virtual: scheduled delivery\n"); } else can_msgobj_clear_fl(obj,TX_LOCK); @@ -325,7 +325,7 @@ void virtual_do_tx_timeout(unsigned long data) /* Free transmitted slot */ canque_free_outslot(obj->qends, obj->tx_qedge, obj->tx_slot); obj->tx_slot=NULL; - CANMSG("virtual: delayed delivery\n"); + DEBUGMSG("virtual: delayed delivery\n"); } can_msgobj_clear_fl(obj,TX_LOCK); @@ -355,7 +355,7 @@ int virtual_wakeup_tx(struct chip_t *chip, struct msgobj_t *obj) while((cmd=canque_test_outslot(obj->qends, &qedge, &slot)) >= 0){ if(cmd==0) { canque_filter_msg2edges(obj->qends, &slot->msg); - CANMSG("virtual: direct delivery\n"); + DEBUGMSG("virtual: direct delivery\n"); } canque_free_outslot(obj->qends, qedge, slot); } -- 2.39.2