linux/drivers/mcst/mckk/linux_mckk.c

8790 lines
266 KiB
C

/*
* Copyright (c) 1996 by MCST.
* MC Board Driver general functions (MCKK).
*/
/*
* Standard system includes
*/
#define MCKK_BUS_TYPE DDI_SBUS_SPARC
#include <linux/miscdevice.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/io.h>
#include <asm/dma.h>
#include "linux_mckk_match.h"
//#include <linux/mcst/linux_me90_int.h>
#define DBGMCKK_MODE 0
#define dbgmckk if(DBGMCKK_MODE) printk
#define MCKK_INTERRUPT_DEBUG 0
#if MCKK_INTERRUPT_DEBUG
#define INTERRUPT_REG_BASE 0xf1410000
#define INTERRUPT_MASK_REG 0x4
#define INTERRUPT_MASK_CLEAR 0x8
#define INTERRUPT_MASK_SET 0xc
#define mcst_read(__reg) \
({ u32 __ret; \
__asm__ __volatile__("lda [%1] %2, %0" \
: "=r" (__ret) \
: "r" (__reg), "i" (0x2f) \
: "memory"); \
__ret; \
})
#define mcst_write(__reg, __val) \
({ __asm__ __volatile__("sta %0, [%1] %2" \
: \
: "r" (__val), "r" (__reg), "i" (0x2f) \
: "memory"); })
#endif /* MCKK_INTERRUPT_DEBUG */
/*
* Prototypes for this module
*/
static int mckk_open(struct inode *inode, struct file *file);
static int mckk_close(struct inode *inode, struct file *file);
static int mckk_ioctl (struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
static unsigned int mckk_chpoll(struct file *file, struct poll_table_struct *wait);
static int mckk_mmap(struct file *file, struct vm_area_struct *vma);
static ssize_t mckk_read(struct file *pfile, char *buf, size_t sz, loff_t *lf);
static ssize_t mckk_write(struct file *pfile, const char *buf, size_t sz, loff_t *lf);
static irqreturn_t mckk_interrupt(int irq, void* arg);
static irqreturn_t mckk_intr_thread_handler(int irq, void* arg);
static int abort_dma_transfer(mcb_state_t *state, int channel);
#if IS_ENABLED(CONFIG_PCI2SBUS)
extern void p2s_reg_print(u8 val);
#endif
#define MCKK_NAME "MCST,mckk"
static int mckk_major;
#define MAX_MCKK_INSTANCES 16
static mcb_state_t *mckk_states[MAX_MCKK_INSTANCES];
struct mckk_file_private {
int count;
int instance;
dev_t dev;
};
#define file_mckk_state(file) \
mckk_states[((struct mckk_file_private*)file->private_data)->instance]
#define file_mckk_dev(file) ((struct mckk_file_private*)file->private_data)->dev
/*
* file_operations of mckk
*/
const static struct file_operations mckk_fops = {
owner: THIS_MODULE,
ioctl: mckk_ioctl,
open: mckk_open,
poll: mckk_chpoll,
mmap: mckk_mmap,
read: mckk_read,
write: mckk_write,
release: mckk_close,
};
// THIS FUNCTION MUST GO OF BUS ARCH INPLEMENTATION
int mcst_of_io_remap(struct of_device *op, int reg_set_num,
off_t offset, size_t len,
struct vm_area_struct *vma)
{
// О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫ О©╫ О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫.
return -1;
}
// HERE ARE BUS SPECIFIC FUNCTIONS
#include <asm/of_device.h>
static int
mckk_nregs(mcb_state_t *state)
{
struct of_device *op = state->op;
struct resource *res = op->resource;
int i;
for ( i = 0; i < PROMREG_MAX; i++ ) {
if ( res[i].end == 0 ) {
break;
}
}
return i;
}
static int inline mckk_request_irq(mcb_state_t *state)
{
#ifdef __e2k__
printk("request irq PCI 2 SBUS\n");
#else
return request_threaded_irq(state->op->irqs[0], mckk_interrupt,
mckk_intr_thread_handler,
IRQF_SHARED | IRQF_DISABLED | IRQF_ONESHOT,
"mckk", state);
#endif
}
static void inline mckk_free_irq(mcb_state_t *state)
{
#ifdef __e2k__
printk("free irq PCI 2 SBUS\n");
#else
free_irq(state->op->irqs[0], state);
#endif
}
static inline int mckk_clock_freq(mcb_state_t *state)
{
return state->op->clock_freq;
}
static inline int mckk_io_remap_page(mcb_state_t *state, int reg_set_num,
off_t offset, size_t len, struct vm_area_struct *vma)
{
return mcst_of_io_remap(state->op, reg_set_num, offset, len, vma);
}
static inline void *mckk_ioremap(mcb_state_t *state, int reg_set_num)
{
struct of_device *op = state->op;
return of_ioremap(&op->resource[reg_set_num], 0,
resource_size(&op->resource[reg_set_num]), "MCST,mckk/sbus");
}
static void inline mckk_iounmap(mcb_state_t *state, int reg_set_num, void *addr)
{
of_iounmap(&state->op->resource[reg_set_num], addr,
resource_size(&state->op->resource[reg_set_num]));
}
static inline unsigned long mckk_dma_alloc_coherent(mcb_state_t *state, size_t size,
dma_addr_t *dma_handle)
{
return (unsigned long)dma_alloc_coherent(&state->op->dev, size, dma_handle, GFP_KERNEL);
}
static inline int mckk_dma_sync(mcb_state_t *state, dma_addr_t ba,
size_t size, int dir)
{
dma_sync_single_for_cpu(&state->op->dev, ba, size, dir);
return 0;
}
static inline void mckk_dma_free_coherent(mcb_state_t *state, size_t size,
unsigned long cpu_addr, dma_addr_t dma_handle)
{
dma_free_coherent(&state->op->dev, size, (void *)cpu_addr, dma_handle);
}
// HERE IS THE BEGINING OF DRIVER GENERAL BODY
static void mckk_buf_trans_done(mcb_state_t * state,
int channel,
/* buf_t * bp*/
uio_t * uio_p
);
static int put_drq_queue(/*struct buf * bp*/ uio_t *uio_p,
mcb_state_t * state
);
static int start_pending_transfer(mcb_state_t * state,
int channel,
#ifdef _MP_TIME_USE_
u_int intr_drq_received
#else
hrtime_t intr_drq_received
#endif /* _MP_TIME_USE_ */
);
static void remove_drq_queue(mcb_state_t * state,
int channel
);
static int handle_mp_timer_intr(mcb_state_t * state,
#ifdef _MP_TIME_USE_
u_int intr_mp_time
#else
hrtime_t intr_mp_time
#endif /* _MP_TIME_USE_ */
);
static int service_mp_timer_intr_request(mcb_state_t * state,
u_int timer_interval,
#ifdef _MP_TIME_USE_
u_int intr_receiving_time
#else
hrtime_t intr_receiving_time
#endif /* _MP_TIME_USE_ */
);
static int service_mp_timer_intr(mcb_state_t * state,
mp_tm_intr_info_t * mp_timer_intr_info,
u_int request_interval,
#ifdef _MP_TIME_USE_
u_int request_receiving_time
#else
hrtime_t request_receiving_time
#endif /* _MP_TIME_USE_ */
);
static void clean_mp_timer_intr_info(mp_tm_intr_info_t * mp_timer_intr_info);
static void remove_mp_timer_intr(mcb_state_t *state);
static int get_channel_state (mcb_state_t * state,
int channel,
trans_state_t transfer_state
);
static int start_mckk_dma_engine(mcb_state_t * state,
int channel
);
static int mckk_mmap(struct file *file, struct vm_area_struct *vma);
static intr_reason_t get_intr_reason(mcb_state_t * state,
sparc_drv_args_t * interrupt_args,
#ifdef _MP_TIME_USE_
u_int intr_receiving_time
#else
hrtime_t intr_receiving_time
#endif /* _MP_TIME_USE_ */
);
static int mckk_set_dma_trans_results(
mcb_state_t * state,
int channel,
trans_buf_t * trans_buf_p,
trans_spec_t * transfer_spec,
size_t moved_data_size
);
static void mckk_init_trans_results(trans_spec_t * transfer_spec);
static int mckk_create_trans_header(
mcb_state_t *state,
int buf_byte_size,
int pseudobuf_flag,
int flags,
trans_buf_t *source_buf,
/* buf_t *bp, */
uio_t *uio_p,
mcb_drv_buf_t *drv_buf_p,
trans_buf_t **new_trans_buf_p
);
static void mckk_init_trans_header(
mcb_state_t *state,
trans_buf_t *trans_buf_p
);
static int mckk_create_drv_buf(mcb_state_t * state,
uio_t * uio_p,
int op_flags,
trans_spec_t * transfer_spec,
mcb_drv_buf_t ** new_trans_drv_buf_p
);
static void mckk_delete_drv_buf(mcb_state_t * state,
mcb_drv_buf_t * trans_drv_buf_p
);
static void mckk_connection_polling_intr(mcb_state_t * state,
int connection_refused,
hrtime_t intr_receiving_time
);
static void write_all_general_regs(
volatile mc_cntr_st_reg_t *general_regs,
mc_reg_type_t write_regs_mask,
mc_wr_reg_t TLRM_write_value,
mc_rd_reg_t *benchmark_value,
mc_wr_reg_t TRM_TRCWD_write_value
);
static int compare_general_regs(volatile mc_cntr_st_reg_t * general_regs,
mc_reg_type_t read_regs_mask,
mc_reg_type_t cmp_regs_mask,
mc_rd_reg_t benchmark_value
);
/*
* Driver execution modes
*/
#ifndef __KEEP_LAST_TRANS_RES__
static int keep_last_trans_buf_mode = 0;
#else
static int keep_last_trans_buf_mode = 1;
#endif /* __KEEP_LAST_TRANS_RES__ */
/*
* Debug message control
* Debug Levels:
* 0 = no messages
* 1 = Errors
* Can be set with adb or in the /etc/system file with
* "set state:me90drv_debug=<value>"
* Defining DEBUG on the compile line (-DDEBUG) will enable debugging
* statements in this driver, and will also enable the ASSERT statements.
*/
int me90drv_log_msg_num = 0;
#ifdef DEBUG
int me90drv_debug = 3;
int me90drv_max_log_msg_num = 3200;
//int me90drv_max_log_msg_num = 32;
#else
int me90drv_debug = 2;
//int me90drv_debug = 0;
int me90drv_max_log_msg_num = 10;
#endif /* DEBUG */
#define DBGMCKKDETAIL_MODE 0
#define dbgmckkdetail if(DBGMCKKDETAIL_MODE) printk
/*
* The driver modes and state info
*/
int me90_sbus_clock_freq = 0;
int me90_sbus_nsec_cycle = 0;
int me90_mp_clock_freq = 0;
int me90_mp_nsec_cycle = 0;
#ifdef DEBUG_BUF_USE
char me90_debug_msg_buf[ME90_DEBUG_MSG_LINE_SIZE *
ME90_DEBUG_MSG_LINE_NUM
];
#else
char *me90_debug_msg_buf = NULL;
#endif /* DEBUG_BUF_USE */
int me90_debug_buf_line = 0;
int me90_debug_buf_overflow = 0;
/*
* Log a message to the console and/or syslog with cmn_err
*/
/*ARGSUSED*/
static void me90_log(mcb_state_t *state, int level, const char *fmt, ...)
{
char name[16];
char buf[1024];
va_list ap;
#ifdef DEBUG_BUF_USE
int cur_line = 0;
#endif /* DEBUG_BUF_USE */
switch (level) {
case CE_CONT:
case CE_NOTE:
case CE_WARN:
case CE_PANIC:
if (state) {
(void) sprintf(name, "%s%d", "mckk",
state->inst);
} else {
(void) sprintf(name, "mckk");
}
va_start(ap, fmt);
(void) vsprintf(buf, fmt, ap);
va_end(ap);
printk(KERN_ALERT "%s:\t%s", name, buf);
break;
/* case ME90_DL_REGS_OP: if (me90drv_debug < 4) break; */
/* case ME90_DL_MINOR: if (me90drv_debug < 4) break; */
case ME90_DL_REGS_MAP: if (me90drv_debug < 4) break;
/*FALLTHROUGH*/
case ME90_DL_TRACE: if (me90drv_debug < 3) break;
/*FALLTHROUGH*/
case ME90_DL_WARNING: if (me90drv_debug < 2) break;
/*FALLTHROUGH*/
case ME90_DL_ERROR: if (me90drv_debug < 1) break;
default:
if (me90drv_log_msg_num > me90drv_max_log_msg_num)
break;
if (state) {
(void) sprintf(name, "mckk%d", state->inst);
} else {
(void) sprintf(name, "mckk");
}
if (me90drv_log_msg_num < me90drv_max_log_msg_num) {
va_start(ap, fmt);
(void) vsprintf(buf, fmt, ap);
va_end(ap);
} else {
(void) sprintf(buf, "too many errors masseges: driver"
" turn on the silent mode\n");
}
#ifdef DEBUG_BUF_USE
cur_line = me90_debug_buf_line;
me90_debug_buf_line ++;
if (me90_debug_buf_line >= ME90_DEBUG_MSG_LINE_NUM)
{
me90_debug_buf_line = 0;
me90_debug_buf_overflow = 1;
};
buf[ME90_DEBUG_MSG_LINE_SIZE - 1] = 0;
sprintf(&me90_debug_msg_buf[cur_line *
ME90_DEBUG_MSG_LINE_SIZE
],
"%s:\t%s",
name, buf
);
#else
printk(KERN_ERR "^%s:\t%s", name, buf);
me90drv_log_msg_num ++;
#if defined(DEBUG) || defined(__KMMEM_ALLOC_DEBUG__)
// Sol ticks delay(1 * drv_usectohz(10000));
/* Lin mksec */ udelay(1 * 10000);
#endif /* DEBUG or __KMMEM_ALLOC_DEBUG__ */
#endif /* DEBUG_BUF_USE */
break;
}
}
/*
* Wait for finish of an asynchronous I/O transfer
*/
/*ARGSUSED*/
static int
me90_wait_async_trans(
mcb_state_t *state,
int channel,
int waiting_time,
me90drv_trans_buf_t **trans_buf_pp)
{
me90drv_chnl_state_t *channel_state = NULL;
u_long cur_clock_ticks = 0;
u_long timeout_clock_ticks = 0;
int rval = 0;
ME90_LOG(state, ME90_DL_TRACE,
"mckk_wait_async_trans started for channel %d\n", channel);
channel_state = &state -> all_channels_state[channel];
mutex_enter(&state->mutex); /* start MUTEX */
if (channel_state -> async_trans_num <= 0) {
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_ERROR,
"mckk_wait_async_trans there are no outstanding"
" asynchronous requests for channel %d\n", channel);
return EINVAL;
}
if (waiting_time > 0) {
drv_getparm(LBOLT,&cur_clock_ticks);
timeout_clock_ticks = cur_clock_ticks +
drv_usectohz(waiting_time);
}
while (channel_state -> ready_atrans_start == NULL) {
if (waiting_time > 0) {
rval = cv_timedwait(&state -> atrans_end_cv,
&state->mutex, timeout_clock_ticks);
} else if (waiting_time == 0) {
rval = ETIME;
break;
} else
rval = cv_wait(&state -> atrans_end_cv,
&state->mutex);
if (rval < 0) {
rval = ETIME;
break;
} else if (rval == 0) {
rval = EINTR;
break;
} else {
rval = 0;
}
}
if (rval != 0 || channel_state -> ready_atrans_start == NULL) {
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_TRACE,
"mckk_wait_async_trans waiting finished inefficiently"
" for channel %d\n", channel);
return rval;
}
*trans_buf_pp = channel_state -> ready_atrans_start;
channel_state -> ready_atrans_start =
channel_state -> ready_atrans_start -> next_trans_buf;
if (channel_state -> ready_atrans_start == NULL)
channel_state -> ready_atrans_end = NULL;
channel_state -> ready_atrans_size --;
channel_state -> async_trans_num --;
mutex_exit(&state->mutex); /* end MUTEX */
#ifdef __BLOCK_BUFFER_USE__
if ((*trans_buf_pp) -> trans_buf_desc.drv_buf_used)
#endif /* __BLOCK_BUFFER_USE__ */
me90drv_finish_drv_buf_trans(state, channel, *trans_buf_pp);
ME90_LOG(state, ME90_DL_TRACE,
"mckk_wait_async_trans succeeded for channel %d\n", channel);
return 0;
}
/*
* Driver mmap entry point
*/
/*ARGSUSED*/
static int
mckk_mmap(struct file *file, struct vm_area_struct *vma)
{
mcb_state_t *state = file_mckk_state(file);
dev_t dev = file_mckk_dev(file);
int instance;
int channel;
caddr_t mapped_reg_set_p = NULL;
off_t reg_set_offset = 0;
unsigned long off = (long )(vma->vm_pgoff << PAGE_SHIFT);
size_t reg_set_len;
ME90_LOG(NULL, ME90_DL_TRACE, "%s(): started\n", __func__);
instance = MCB_INST(dev);
channel = MCB_CHAN(dev);
if ( state == NULL ) {
printk("~%s~_mmap: unattached instance %d\n", mod_name, instance);
return (ENXIO);
}
#ifdef DEBUG
ME90_LOG(NULL, ME90_DL_REGS_MAP,
"%s(): instance %d channel %d started with off 0x%x\n", __func__,
instance, channel,
off
);
#endif /* DEBUG */
if ( off >= MC_EPROM_REG_SET_OFFSET &&
(off < MC_EPROM_REG_SET_OFFSET + MC_EPROM_REG_SET_LEN) ) {
ME90_LOG(state, ME90_DL_REGS_MAP, "%s(): register set is EPROM\n", __func__);
if ( state->MC_EPROM_CADDR != NULL ) { /* With eprom */
reg_set_offset = off - MC_EPROM_REG_SET_OFFSET;
reg_set_len = MC_EPROM_REG_SET_LEN;
vma->vm_flags |= (VM_IO | VM_LOCKED | VM_READ | VM_WRITE );
if ( mckk_io_remap_page(state, 0, reg_set_offset, reg_set_len, vma) ) {
printk ("Error map range array\n");
return -EAGAIN;
}
} else { /* Without eprom */
ME90_LOG(state, ME90_DL_ERROR,
"%s(): invalid register set off 0x%x\n", __func__,
off
);
return -1;
}
} else if ( off >= MC_CNTR_ST_REG_SET_OFFSET && off < MC_CNTR_ST_REG_SET_OFFSET + MC_CNTR_ST_REG_SET_LEN ) {
ME90_LOG(state, ME90_DL_REGS_MAP,
"%s(): register set is GEN REGS\n", __func__
);
reg_set_offset = off - MC_CNTR_ST_REG_SET_OFFSET;
reg_set_len = MC_CNTR_ST_REG_SET_LEN;
vma->vm_flags |= (VM_IO | VM_LOCKED | VM_READ | VM_WRITE );
if ( state->MC_EPROM_CADDR != NULL ) { /* With eprom */
if ( mckk_io_remap_page(state, 1, reg_set_offset, reg_set_len, vma)) {
printk ("Error map range array \n");
return -EAGAIN;
}
} else { /* Without eprom */
if ( mckk_io_remap_page(state, 0, reg_set_offset, reg_set_len, vma) ) {
printk ("Error map range array\n");
return -EAGAIN;
}
}
} else if ( off >= MC_BMEM_REG_SET_OFFSET && off < MC_BMEM_REG_SET_OFFSET + MC_BMEM_REG_SET_LEN ) {
ME90_LOG(state, ME90_DL_REGS_MAP, "%s(): register set is BMEM\n", __func__);
reg_set_offset = off - MC_BMEM_REG_SET_OFFSET;
reg_set_len = MC_BMEM_REG_SET_LEN;
vma->vm_flags |= (VM_IO | VM_LOCKED | VM_READ | VM_WRITE );
if ( state->MC_EPROM_CADDR != NULL ) { /* With eprom */
if ( mckk_io_remap_page(state, 2, reg_set_offset, reg_set_len, vma) ) {
printk("Error map range array\n");
return -EAGAIN;
}
} else { /* Without eprom */
if ( mckk_io_remap_page(state, 1, reg_set_offset, reg_set_len, vma) ) {
printk("Error map range array\n");
return -EAGAIN;
}
}
} else {
ME90_LOG(state, ME90_DL_ERROR,
"%s(): invalid register set off 0x%x\n", __func__,
off
);
return -1;
}
#ifdef DEBUG
printk("%s(): succeeded\n", __func__);
#endif
ME90_LOG(state, ME90_DL_REGS_MAP,
"%s(): successed for 0x%x + 0x%x\n", __func__,
mapped_reg_set_p,reg_set_offset
);
return 0;
}
/*
* Read general registers state
*/
/*ARGSUSED*/
static void
read_general_regs(
volatile mc_cntr_st_reg_t *general_regs,
mc_reg_type_t read_regs_mask,
mc_rd_reg_t *read_value)
{
// ME90_LOG(NULL, ME90_DL_TRACE,"read_general_regs started\n");
if (read_regs_mask & TI_mc_reg_type)
{
read_value -> RGEN_read = general_regs -> MC_TI_read;
/* ME90_LOG(NULL, ME90_DL_REGS_OP,"Read GEN REGS: address %02x value %08x\n",
offsetof(mc_cntr_st_reg_rd_t,TI),
read_value -> RGEN_read
);*/
}
else if (read_regs_mask & TMI_mc_reg_type)
{
read_value -> RGEN_read = general_regs -> MC_TMI_read;
/* ME90_LOG(NULL, ME90_DL_REGS_OP,"Read GEN REGS: address %02x value %08x\n",
offsetof(mc_cntr_st_reg_rd_t,TMI),
read_value -> RGEN_read
);*/
}
else if (read_regs_mask & TRM_mc_reg_type)
{
read_value -> RGEN_read = general_regs -> MC_TRM_read;
/* ME90_LOG(NULL, ME90_DL_REGS_OP,"Read GEN REGS: address %02x value %08x\n",
offsetof(mc_cntr_st_reg_rd_t,TRM),
read_value -> RGEN_read
);*/
}
else if (read_regs_mask & TRCWD_mc_reg_type)
{
ME90_LOG(NULL, ME90_DL_ERROR,
"Read write only TRCWD general registers\n"
);
}
else if (read_regs_mask & TLRM_mc_reg_type)
{
read_value -> RGEN_read = general_regs -> MC_TLRM_read;
/* ME90_LOG(NULL, ME90_DL_REGS_OP,"Read GEN REGS: address %02x value %08x\n",
offsetof(mc_cntr_st_reg_rd_t,TLRM),
read_value -> RGEN_read
);*/
}
else if (read_regs_mask & TISB_mc_reg_type)
{
read_value -> RGEN_read = general_regs -> MC_TISB_read;
/* ME90_LOG(NULL, ME90_DL_REGS_OP,"Read GEN REGS: address %02x value %08x\n",
offsetof(mc_cntr_st_reg_rd_t,TISB),
read_value -> RGEN_read
);*/
}
else if (read_regs_mask & TSB_mc_reg_type)
{
read_value -> RGEN_read = general_regs -> MC_TSB_read;
/* ME90_LOG(NULL, ME90_DL_REGS_OP,"Read GEN REGS: address %02x value %08x\n",
offsetof(mc_cntr_st_reg_rd_t,TSB),
read_value -> RGEN_read
);*/
}
else if (read_regs_mask & TPSB_mc_reg_type)
{
read_value -> RGEN_read = general_regs -> MC_TPSB_read;
/* ME90_LOG(NULL, ME90_DL_REGS_OP,"Read GEN REGS: address %02x value %08x\n",
offsetof(mc_cntr_st_reg_rd_t,TPSB),
read_value -> RGEN_read
);*/
}
else if (read_regs_mask & RTM_mc_reg_type)
{
read_value -> RGEN_read = general_regs -> MC_RTM_read;
/* ME90_LOG(NULL, ME90_DL_REGS_OP,"Read GEN REGS: address %02x value %08x\n",
offsetof(mc_cntr_st_reg_rd_t,RTM_READ),
read_value -> RGEN_read
);*/
}
else if ((read_regs_mask & RERR_mc_reg_type) ||
(read_regs_mask & RNC_mc_reg_type)
)
{
read_value -> RGEN_read = general_regs -> MC_RERR_RNC_read;
/* ME90_LOG(NULL, ME90_DL_REGS_OP,"Read GEN REGS: address %02x value %08x\n",
offsetof(mc_cntr_st_reg_rd_t,RERR_RNC),
read_value -> RGEN_read
);*/
}
else
{
read_value -> RGEN_read = general_regs -> MC_RGENS_read;
/* ME90_LOG(NULL, ME90_DL_REGS_OP,"Read GEN REGS: address %02x value %08x\n",
offsetof(mc_cntr_st_reg_rd_t,RGEN_READ),
read_value -> RGEN_read
);*/
}
// ME90_LOG(NULL, ME90_DL_TRACE,"read_general_regs successed\n");
}
/*
* Write general registers
*/
/*ARGSUSED*/
static void
write_general_regs(
volatile mc_cntr_st_reg_t *general_regs,
mc_reg_type_t write_regs_mask,
mc_wr_reg_t TLRM_write_value,
mc_rd_reg_t *benchmark_value)
{
write_all_general_regs(general_regs, write_regs_mask, TLRM_write_value,
benchmark_value, TLRM_write_value);
}
/*
* Write general registers
*/
/*ARGSUSED*/
static void
write_all_general_regs(
volatile mc_cntr_st_reg_t *general_regs,
mc_reg_type_t write_regs_mask,
mc_wr_reg_t TLRM_write_value,
mc_rd_reg_t *benchmark_value,
mc_wr_reg_t TRM_TRCWD_write_value)
{
ME90_LOG(NULL, ME90_DL_TRACE,"write_all_general_regs started\n");
if (write_regs_mask == 0)
{
ME90_LOG(NULL, ME90_DL_ERROR,
"write_all_general_regs: empty mask of general registers "
"to write\n");
return;
};
if (write_regs_mask & TGRM_mc_reg_type)
{
ME90_LOG(NULL, ME90_DL_REGS_OP,"Write TGRM (general reset)\n");
general_regs -> MC_TGRM_write = 0;
benchmark_value -> TI_read = 0;
benchmark_value -> TMI_read = 0;
benchmark_value -> TRM_read = 1;
benchmark_value -> TLRM_read = 1;
benchmark_value -> TISB_read = 0;
benchmark_value -> TSB_read = 0;
benchmark_value -> TPSB_read = 0;
benchmark_value -> RNC_read = 0;
};
if ((write_regs_mask & TRM_mc_reg_type) ||
(write_regs_mask & TRCWD_mc_reg_type)
)
{
ME90_LOG(NULL, ME90_DL_REGS_OP,"Write TRM %x and TRCWD %x\n",
TRM_TRCWD_write_value.TRM_write,
TRM_TRCWD_write_value.TRCWD_write
);
general_regs -> MC_TRM_TRCWD_write = TRM_TRCWD_write_value.RGEN_write;
benchmark_value -> TRM_read = TRM_TRCWD_write_value.TRM_write;
};
if (write_regs_mask & TI_mc_reg_type)
{
ME90_LOG(NULL, ME90_DL_REGS_OP,"Write TI %x\n",
TLRM_write_value.TI_write
);
general_regs -> MC_TI_write = TLRM_write_value.RGEN_write;
benchmark_value -> TI_read = TLRM_write_value.TI_write;
};
if (write_regs_mask & TMI_mc_reg_type)
{
ME90_LOG(NULL, ME90_DL_REGS_OP,"Write TMI %x\n",
TLRM_write_value.TMI_write
);
general_regs -> MC_TMI_write = TLRM_write_value.RGEN_write;
benchmark_value -> TMI_read = TLRM_write_value.TMI_write;
};
if (write_regs_mask & TLRM_mc_reg_type)
{
ME90_LOG(NULL, ME90_DL_REGS_OP,"Write TLRM %x\n",
TLRM_write_value.TLRM_write
);
general_regs -> MC_TLRM_write = TLRM_write_value.RGEN_write;
benchmark_value -> TLRM_read = TLRM_write_value.TLRM_write;
};
if (write_regs_mask & TISB_mc_reg_type)
{
ME90_LOG(NULL, ME90_DL_REGS_OP,"Write TISB %x\n",
TLRM_write_value.TISB_write
);
general_regs -> MC_TISB_write = TLRM_write_value.RGEN_write;
benchmark_value -> TISB_read = TLRM_write_value.TISB_write;
};
if (write_regs_mask & TSB_mc_reg_type)
{
ME90_LOG(NULL, ME90_DL_REGS_OP,"Write TSB %x\n",
TLRM_write_value.TSB_write
);
general_regs -> MC_TSB_write = TLRM_write_value.RGEN_write;
benchmark_value -> TSB_read = TLRM_write_value.TSB_write;
};
if (write_regs_mask & TPSB_mc_reg_type)
{
ME90_LOG(NULL, ME90_DL_REGS_OP,"Write TPSB %x\n",
TLRM_write_value.TPSB_write
);
general_regs -> MC_TPSB_write = TLRM_write_value.RGEN_write;
benchmark_value -> TPSB_read = TLRM_write_value.TPSB_write;
};
if (write_regs_mask & RTM_mc_reg_type)
{
ME90_LOG(NULL, ME90_DL_ERROR,"Write read only RTM general registers\n");
};
if ((write_regs_mask & RERR_mc_reg_type) ||
(write_regs_mask & RNC_mc_reg_type)
)
{
ME90_LOG(NULL, ME90_DL_REGS_OP,"Write RERR %x and RNC %x\n",
TLRM_write_value.RERR_write,
TLRM_write_value.RNC_write
);
general_regs -> MC_RERR_RNC_write = TLRM_write_value.RGEN_write;
benchmark_value -> RERR_read = TLRM_write_value.RERR_write;
benchmark_value -> RNC_read = TLRM_write_value.RNC_write;
};
if (benchmark_value -> TRM_read == 1)
{
benchmark_value -> TI_read = 0;
benchmark_value -> TMI_read = 0;
benchmark_value -> TISB_read = 0;
benchmark_value -> TSB_read = 0;
benchmark_value -> TPSB_read = 0;
};
ME90_LOG(NULL, ME90_DL_TRACE,"write_all_general_regs finished\n");
}
#if 0 // NOT USED
/*
* Rotate bytes of the word (big and litle endian compatibility)
*/
/*ARGSUSED*/
static u_int mckk_rotate_word_bytes(u_int source_word)
{
u_int new_word = 0;
u_char * new_word_p = (u_char *) &new_word;
u_char * source_word_p = (u_char *) &source_word;
int cur_byte = 0;
for (cur_byte = 0; cur_byte < sizeof(u_int); cur_byte ++)
{
new_word_p[(sizeof(u_int)-1) - cur_byte] = source_word_p[cur_byte];
}
return new_word;
}
#endif // NOT USED
/*
* Delete connection polling mode only for the SPRAC driver,
* mutex_enter must be done by caller
*/
/*ARGSUSED*/
static void
mcb_delete_connection_polling(
mcb_state_t *state,
int reset_error)
{
ME90_LOG(state, ME90_DL_TRACE,"mckk_delete_connection_polling started \n");
if (!(state -> connection_state & MODE_ON_CONNECTION_STATE) ||
(state -> connection_state & MODE_OFF_CONNECTION_STATE)
)
{
ME90_LOG(state, ME90_DL_TRACE,
"mckk_delete_connection_polling polling mode is not set\n"
);
}
state -> connection_state &= ~MODE_ON_CONNECTION_STATE;
state -> connection_state |= MODE_OFF_CONNECTION_STATE;
state -> cnct_polling_error = reset_error;
cv_broadcast(&state -> cnct_polling_cv);
ME90_LOG(state, ME90_DL_TRACE,"mckk_delete_connection_polling successed \n");
return;
}
/*
* Compare general registers state with benchmark value
*/
/*ARGSUSED*/
static int compare_general_regs(
volatile mc_cntr_st_reg_t * general_regs,
mc_reg_type_t read_regs_mask,
mc_reg_type_t cmp_regs_mask,
mc_rd_reg_t benchmark_value
)
{
int errors_num = 0;
mc_rd_reg_t read_value;
mc_rd_reg_t cmp_value_mask;
ME90_LOG(NULL, ME90_DL_TRACE,"compare_general_regs started\n");
if (cmp_regs_mask == 0)
{
ME90_LOG(NULL, ME90_DL_ERROR,
"compare_general_regs: empty mask of general registers\n"
);
return errors_num;
};
read_value.RGEN_read = 0;
read_general_regs(general_regs,read_regs_mask,&read_value);
cmp_value_mask.RGEN_read = 0;
if (cmp_regs_mask & TI_mc_reg_type)
cmp_value_mask.TI_read = ~0;
if (cmp_regs_mask & TMI_mc_reg_type)
cmp_value_mask.TMI_read = ~0;
if (cmp_regs_mask & TRM_mc_reg_type)
cmp_value_mask.TRM_read = ~0;
if (cmp_regs_mask & TRCWD_mc_reg_type)
{
ME90_LOG(NULL, ME90_DL_ERROR,
"compare_general_regs write only TRCWD general registers\n"
);
};
if (cmp_regs_mask & TLRM_mc_reg_type)
cmp_value_mask.TLRM_read = ~0;
if (cmp_regs_mask & TISB_mc_reg_type)
cmp_value_mask.TISB_read = ~0;
if (cmp_regs_mask & TSB_mc_reg_type)
cmp_value_mask.TSB_read = ~0;
if (cmp_regs_mask & TPSB_mc_reg_type)
cmp_value_mask.TPSB_read = ~0;
if (cmp_regs_mask & RTM_mc_reg_type)
cmp_value_mask.RTM_read = ~0;
if (cmp_regs_mask & RERR_mc_reg_type)
cmp_value_mask.RERR_read = ~0;
if (cmp_regs_mask & RNC_mc_reg_type)
cmp_value_mask.RNC_read = ~0;
if ((read_value.RGEN_read & cmp_value_mask.RGEN_read) !=
(benchmark_value.RGEN_read & cmp_value_mask.RGEN_read)
)
{
ME90_LOG(NULL, ME90_DL_ERROR,
"different general regs state 0x%08x and benchmarck 0x%08x"
" mask 0x%08x\n",
read_value.RGEN_read,
benchmark_value.RGEN_read,
cmp_value_mask.RGEN_read
);
errors_num ++;
};
ME90_LOG(NULL, ME90_DL_TRACE,"compare_general_regs finished with %d error\n",
errors_num
);
return errors_num;
}
/*
* Reset general registers and MicroProcessor
*/
/*ARGSUSED*/
static int
reset_general_regs(
mcb_state_t *state,
int mp_state)
{
mc_wr_reg_t intr_reset_value;
mc_wr_reg_t pre_stop_mp_value;
mc_wr_reg_t pre_trcwd_stop_mp_value;
mc_wr_reg_t stop_mp_value;
mc_wr_reg_t trcwd_stop_mp_value;
mc_wr_reg_t startup_mp_value;
mc_wr_reg_t trcwd_startup_mp_value;
mc_wr_reg_t post_startup_mp_value;
mc_wr_reg_t post_trcwd_startup_mp_value;
mc_rd_reg_t benchmark_value;
int errors_num = 0;
ME90_LOG(state, ME90_DL_TRACE, "reset_general_regs started MP %s\n",
(mp_state == 1) ? "HALTED" :
(mp_state == 2) ? "LOCKED" : "STARTED");
state->mp_state = undef_mp_state;
benchmark_value.RGEN_read = 0;
read_general_regs(state->MC_CNTR_ST_REGS,TI_mc_reg_type,&benchmark_value);
// benchmark_value.RTM_read = get_state_module_type(state -> type_unit);
benchmark_value.RTM_read = mckk_rtm_encode;
intr_reset_value.RGEN_write = 0;
write_general_regs(state -> MC_CNTR_ST_REGS, /* interrupt reset */
TISB_mc_reg_type | RERR_mc_reg_type,
intr_reset_value,
&benchmark_value
);
if (state -> connection_state & MODE_ON_CONNECTION_STATE)
{
ME90_LOG(state, ME90_DL_ERROR,
"reset_general_regs : connection polling mode is set\n"
);
me90drv_delete_connection_polling(state, EINVAL);
}
pre_stop_mp_value.RGEN_write = 0;
pre_stop_mp_value.TLRM_write = 1;
pre_trcwd_stop_mp_value.RGEN_write = 0;
write_all_general_regs(state -> MC_CNTR_ST_REGS, /* set error lock mode */
TLRM_mc_reg_type,
pre_stop_mp_value,
&benchmark_value,
pre_trcwd_stop_mp_value
);
errors_num += compare_general_regs(state -> MC_CNTR_ST_REGS,
TI_mc_reg_type,
all_readable_mc_reg_type,
benchmark_value
);
stop_mp_value.RGEN_write = 0;
trcwd_stop_mp_value.RGEN_write = 0;
trcwd_stop_mp_value.TRM_write = 1;
trcwd_stop_mp_value.TRCWD_write = 1;
write_all_general_regs(state -> MC_CNTR_ST_REGS, /* lock MP and module */
TRM_mc_reg_type | TRCWD_mc_reg_type,
stop_mp_value,
&benchmark_value,
trcwd_stop_mp_value
);
errors_num += compare_general_regs(state -> MC_CNTR_ST_REGS,
TI_mc_reg_type,
all_readable_mc_reg_type,
benchmark_value
);
if (mp_state != 2)
{
if (mp_state == 1)
{
mp_init_area_t *mp_init_area =
(mp_init_area_t *) &state -> MC_BMEM[MC_MP_INIT_AREA_BMEM_ADDR];
mp_init_area -> MP_INIT_AREA_u_long[0] = MP_HALT_OPCODE;
// mckk_rotate_word_bytes(MP_HALT_OPCODE);
};
startup_mp_value.RGEN_write = 0;
trcwd_startup_mp_value.RGEN_write = 0;
trcwd_startup_mp_value.TRM_write = 0;
trcwd_startup_mp_value.TRCWD_write = 0;
write_all_general_regs(state -> MC_CNTR_ST_REGS,/* start up MP and module */
TRM_mc_reg_type | TRCWD_mc_reg_type,
startup_mp_value,
&benchmark_value,
trcwd_startup_mp_value
);
errors_num += compare_general_regs(state -> MC_CNTR_ST_REGS,
TI_mc_reg_type,
all_readable_mc_reg_type,
benchmark_value
);
post_startup_mp_value.RGEN_write = 0;
post_startup_mp_value.TLRM_write = state -> set_tlrm;
post_trcwd_startup_mp_value.RGEN_write = 0;
write_all_general_regs(state -> MC_CNTR_ST_REGS,/* set initial regs state */
all_writable_mc_reg_type,
post_startup_mp_value,
&benchmark_value,
post_trcwd_startup_mp_value
);
errors_num = compare_general_regs(state -> MC_CNTR_ST_REGS,
TI_mc_reg_type,
all_readable_mc_reg_type,
benchmark_value
);
};
if (mp_state == 1) {
state -> mp_state = halted_mp_state;
}
else if (mp_state == 2)
state -> mp_state = locked_mp_state;
if (errors_num > 0)
{
ME90_LOG(state, ME90_DL_ERROR, "reset_general_regs finished with error\n");
}
else
{
ME90_LOG(state, ME90_DL_TRACE, "reset_general_regs succeeded \n");
}
return errors_num;
}
/*
* Create and allocate the transfer buffers
*/
/*ARGSUSED*/
static int
mckk_alloc_trans_bufs(
mcb_state_t *state,
me90drv_trbuf_desc_t *new_trans_buf,
int buf_byte_size,
int flags)
{
int reqlen;
#ifdef DEBUG
printk("mckk_alloc_trans_bufs started with buffer byte size %d\n",
buf_byte_size);
#endif
/* О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫ ME90_ENABLE_BURST_SIZES */
/* reqlen = ((buf_byte_size + (ME90_ENABLE_BURST_SIZES - 1)) /
ME90_ENABLE_BURST_SIZES) * ME90_ENABLE_BURST_SIZES; */
reqlen = ((buf_byte_size + (DMA_MAX_BURST_SIZE_BYTES - 1)) /
DMA_MAX_BURST_SIZE_BYTES) * DMA_MAX_BURST_SIZE_BYTES;
new_trans_buf->dma.dma = mckk_dma_alloc_coherent(state, reqlen,
&new_trans_buf->dma.prim_dev_mem );
if ( new_trans_buf->dma.dma == 0) {
printk ("Cannot get free pages\n");
return -1;
}
new_trans_buf->dma.real_size = reqlen;
new_trans_buf->buf_address = (caddr_t)new_trans_buf->dma.dma;
new_trans_buf->buf_size = reqlen;
dbgmckk("%s(): new_trans_buf -> buf_address = 0x%lx, "
"new_trans_buf -> buf_size = 0x%lx\n", __func__,
(u_long)new_trans_buf->buf_address,
(u_long)new_trans_buf->buf_size);
#ifdef DEBUG
printk("%s(): succeeded for buf 0x%lx with buffer"
"byte size %d\n", __func__, (unsigned long)new_trans_buf, buf_byte_size);
#endif
return 0;
}
/*
* Create any I/O operation transfer buffer header structure
*/
/*ARGSUSED*/
static int
mckk_create_trans_header(
mcb_state_t *state,
int buf_byte_size,
int pseudobuf_flag,
int flags,
trans_buf_t *source_buf,
/* buf_t *bp,*/
uio_t *uio_p,
mcb_drv_buf_t *drv_buf_p,
trans_buf_t **new_trans_buf_p)
{
trans_buf_t * new_trans_buf = NULL;
int rval = 0;
ME90_LOG(state, ME90_DL_TRACE,
"mckk_create_trans_header started with buffer byte size %d\n",
buf_byte_size);
new_trans_buf = kmem_alloc(sizeof(trans_buf_t),KM_NOSLEEP);
if (new_trans_buf == NULL) {
ME90_LOG(state, ME90_DL_ERROR,
"mckk_create_trans_header cannot allocate kernel"
" memory\n");
return EINVAL;
}
new_trans_buf -> next_trans_buf = NULL;
new_trans_buf -> trans_size = buf_byte_size;
if (source_buf != NULL) {
new_trans_buf -> trans_buf_desc.only_link = 1;
new_trans_buf -> trans_buf_desc.drv_buf_used =
source_buf -> trans_buf_desc.drv_buf_used;
new_trans_buf -> trans_buf_desc.uio_p =
source_buf -> trans_buf_desc.uio_p;
new_trans_buf -> trans_buf_desc.buf_address =
source_buf -> trans_buf_desc.buf_address;
new_trans_buf -> trans_buf_desc.buf_size =
source_buf -> trans_buf_desc.buf_size;
/* new_trans_buf -> trans_buf_desc.acc_handle =
source_buf -> trans_buf_desc.acc_handle;
new_trans_buf -> trans_buf_desc.dma_handle =
source_buf -> trans_buf_desc.dma_handle;
new_trans_buf -> trans_buf_desc.cookie =
source_buf -> trans_buf_desc.cookie;*/
new_trans_buf -> trans_buf_desc.dma =
source_buf -> trans_buf_desc.dma;
new_trans_buf -> trans_buf_desc.ccount =
source_buf -> trans_buf_desc.ccount;
new_trans_buf -> pseudobuf = source_buf -> pseudobuf;
new_trans_buf -> batch_flag = source_buf -> batch_flag;
new_trans_buf -> multi_buf_flag = source_buf -> multi_buf_flag;
new_trans_buf -> drv_buf_p = source_buf -> drv_buf_p;
mckk_init_trans_header(state, new_trans_buf);
*new_trans_buf_p = new_trans_buf;
ME90_LOG(state, ME90_DL_TRACE,
"mckk_create_trans_header successed with only link of"
" buffer\n");
return 0;
}
dbgmckk("mckk_create_trans_header: buf_byte_size (bytes) = 0x%x\n", buf_byte_size);
new_trans_buf -> trans_buf_desc.only_link = 0;
new_trans_buf -> trans_buf_desc.drv_buf_used = (uio_p == NULL);
new_trans_buf -> trans_buf_desc.uio_p = uio_p;
new_trans_buf -> pseudobuf = pseudobuf_flag;
new_trans_buf -> batch_flag = 0;
new_trans_buf -> multi_buf_flag = 0;
new_trans_buf -> drv_buf_p = drv_buf_p;
rval = mckk_alloc_trans_bufs(state, &new_trans_buf -> trans_buf_desc,
buf_byte_size, flags);
if (rval != 0) {
kmem_free(new_trans_buf, sizeof(trans_buf_t));
ME90_LOG(state, ME90_DL_TRACE,
"mckk_create_trans_header failed with buffer byte "
"size %d\n", buf_byte_size);
return rval;
}
mckk_init_trans_header(state, new_trans_buf);
*new_trans_buf_p = new_trans_buf;
ME90_LOG(state, ME90_DL_TRACE,
"mckk_create_trans_header successed with buffer byte size %d\n",
buf_byte_size);
return 0;
}
/*
* Set error for the DMA data transfer on private driver buffer
*/
/*ARGSUSED*/
static void
mckk_drv_buf_io_error(
me90drv_trans_buf_t *trans_buf_p,
int error_code)
{
ME90_LOG(NULL, ME90_DL_TRACE,
"mckk_drv_buf_io_error started for trans_buf 0x%lx and "
"error %d\n", trans_buf_p, error_code);
#ifdef __BLOCK_BUFFER_USE__
if (!trans_buf_p -> trans_buf_desc.drv_buf_used ||
trans_buf_p -> drv_buf_p == NULL) {
ME90_LOG(NULL, ME90_DL_TRACE,
"mckk_drv_buf_io_error the transfer has not private"
" buffer\n");
return;
}
#endif /* __BLOCK_BUFFER_USE__ */
trans_buf_p -> trans_error = error_code;
ME90_LOG(NULL, ME90_DL_TRACE,
"mckk_drv_buf_io_error succeeded for trans_buf 0x%lx and"
" error %d\n", trans_buf_p, error_code);
}
/*
* Notify blocked processes waiting for the I/O DMA data transfer on private
* driver buffer to complete
*/
/*ARGSUSED*/
static void mckk_drv_buf_io_done(
mcb_state_t *state,
me90drv_trans_buf_t *trans_buf_p,
int withot_mutex_enter)
{
ME90_LOG(state, ME90_DL_TRACE,
"mckk_drv_buf_io_done started for trans_buf 0x%lx\n",
trans_buf_p);
#ifdef __BLOCK_BUFFER_USE__
if (!trans_buf_p -> trans_buf_desc.drv_buf_used ||
trans_buf_p -> drv_buf_p == NULL) {
ME90_LOG(NULL, ME90_DL_TRACE,
"mckk_drv_buf_io_done the transfer has not private"
" buffer\n");
return;
}
#endif /* __BLOCK_BUFFER_USE__ */
if (!withot_mutex_enter)
{
mutex_enter(&state->mutex); /* start MUTEX */
}
#ifdef __BLOCK_BUFFER_USE__
trans_buf_p -> drv_buf_p -> trans_completed = 1;
cv_broadcast(&trans_buf_p -> drv_buf_p -> trans_finish_cv);
#else
trans_buf_p -> trans_completed = 1;
cv_broadcast(&trans_buf_p -> trans_finish_cv);
#endif /* __BLOCK_BUFFER_USE__ */
if (!withot_mutex_enter)
{
mutex_exit(&state->mutex); /* end MUTEX */
}
ME90_LOG(state, ME90_DL_TRACE,
"mckk_drv_buf_io_done succeeded for trans_buf 0x%lx\n",
trans_buf_p);
}
/*
* Finish the DMA data transfer endgine. Check the device's state registers
* to determine if the trabsfer completed without error. If an error occured
* buf falgs and accordingly buf counters seted
*/
/*ARGSUSED*/
static void
finish_mcb_dma_engine(
mcb_state_t *state,
int channel,
trans_buf_t *trans_buf_p,
int mutex_locked
/*int flags*/)
{
/* buf_t* bp = NULL;*/
uio_t *uio_p = NULL;
mcb_drv_buf_t *drv_buf_p = NULL;
trans_spec_t *transfer_spec = NULL;
int write_op_flag = 0;
u_int transfer_size = 0;
u_int trans_resid = 0;
u_int source_size = 0;
int bad_trans_size = 0;
mc_rd_reg_t board_state;
int miss_data_error = 0;
int sync_rval = 0;
ME90_LOG(state, ME90_DL_TRACE, "%s(): started for channel %d\n", __func__, channel);
source_size = trans_buf_p -> trans_size;
if ( !trans_buf_p -> trans_buf_desc.drv_buf_used ) {
/* bp = trans_buf_p ->trans_buf_desc. bp;
transfer_spec = bp -> b_private;
write_op_flag = bp -> b_flags & B_WRITE;*/
uio_p = trans_buf_p -> trans_buf_desc. uio_p;
transfer_spec = uio_p -> transfer_spec;
write_op_flag = uio_p -> op_flags;
} else {
drv_buf_p = trans_buf_p -> drv_buf_p;
if ( drv_buf_p != NULL )
transfer_spec = drv_buf_p -> transfer_spec;
if ( trans_buf_p -> drv_buf_p == NULL )
write_op_flag = 0;
else
write_op_flag = trans_buf_p -> drv_buf_p -> op_flags & B_WRITE;
}
transfer_size = trans_buf_p -> real_trans_size;
if ( transfer_spec != NULL ) {
if ( transfer_spec -> io_mode_flags & BMEM_TRANSFER_IO_MODE ) {
if ( transfer_spec -> repeation_num > 1 )
source_size *= transfer_spec -> repeation_num;
transfer_size = source_size - transfer_size * transfer_spec->trans_res_info->burst_byte_size;
trans_buf_p -> real_trans_size = transfer_size;
}
}
if ( transfer_size > source_size ) {
bad_trans_size = 1;
ME90_LOG(state, ME90_DL_ERROR,
"%s(): I/O transfer real size %d > "
" source size %d\n", __func__,
transfer_size,
source_size
);
trans_resid = 0;
} else
trans_resid = source_size - transfer_size;
/* if (bp != NULL)
{
bp -> b_resid = trans_resid;
}*/
if ( uio_p != NULL ) {
uio_p -> uio_resid = trans_resid;
}
board_state = trans_buf_p -> gen_reg_state;
if ( transfer_size > 0 && !trans_buf_p -> pseudobuf ) {
int do_sync = 0;
if ( trans_buf_p -> trans_buf_desc.drv_buf_used ) {
if ( trans_buf_p -> drv_buf_p == NULL )
do_sync = 1;
else if ( trans_buf_p -> drv_buf_p -> op_flags & B_READ )
do_sync = 1;
if ( do_sync )
sync_rval = mckk_dma_sync(state,
trans_buf_p -> trans_buf_desc.dma.prim_dev_mem,
trans_buf_p -> trans_buf_desc.buf_size,
DMA_FROM_DEVICE);
} else if ( uio_p != NULL ) {
do_sync = uio_p -> op_flags & B_READ;
if ( do_sync )
sync_rval = mckk_dma_sync(state,
trans_buf_p->trans_buf_desc.dma.prim_dev_mem,
trans_buf_p->trans_buf_desc.uio_p->
uio_iov[0].iov_len,
DMA_FROM_DEVICE);
}
if ( sync_rval != DDI_SUCCESS ) {
ME90_LOG(state, ME90_DL_ERROR,
"%s(): dma_sync failed for channel %d\n", __func__,
channel
);
sync_rval = EFAULT;
}
}
if (/*board_state.RERR_read != 0 ||*/ //alexmipt addition (architecture BUG)
trans_buf_p -> mp_error_code != 0 ||
trans_buf_p -> sparc_error_code != 0 ||
miss_data_error ||
bad_trans_size ||
sync_rval != 0
) {
int rval = EIO;
if ( trans_buf_p -> sparc_error_code != 0 )
rval = trans_buf_p -> sparc_error_code;
else if ( sync_rval != 0 )
rval = sync_rval;
trans_buf_p -> trans_error = rval;
/* if (bp != NULL)
bioerror(bp, rval);
else */
if ( drv_buf_p != NULL )
mckk_drv_buf_io_error(trans_buf_p, rval);
if ( trans_buf_p -> sparc_error_code != 0 &&
trans_buf_p -> sparc_error_code != ETIME ) {
ME90_LOG(state, ME90_DL_ERROR,
"%s(): channel %d I/O transfer finished with error %d"
" detected by SPARC driver\n", __func__,
channel,
trans_buf_p -> sparc_error_code
);
}
#if 0 //alexmipt addition (architecture BUG)
if (board_state.RERR_read != 0)
{
ME90_LOG(state, ME90_DL_ERROR,
"channel %d I/O transfer finished with board internal"
" error RERR = 0x%x RNC = 0x%x RGEN = 0x%08x\n"
,channel,
board_state.RERR_read,
board_state.RNC_read,
board_state.RGEN_read
);
#if IS_ENABLED(CONFIG_PCI2SBUS)
p2s_reg_print(0x4);
p2s_reg_print(0x5);
p2s_reg_print(0x6);
p2s_reg_print(0x7);
#endif
}
#endif
if ( trans_buf_p -> mp_error_code != 0 ) {
if ( trans_buf_p -> board_state_byte != 0 ) {
ME90_LOG(state, ME90_DL_ERROR,
"channel %d I/O transfer finished with error 0x%02x "
"detected by MP driver : "
"SB=0x%02x"
"\n",
channel,
trans_buf_p -> mp_error_code & 0xff,
trans_buf_p -> board_state_byte
);
} else {
ME90_LOG(state, ME90_DL_ERROR,
"channel %d I/O transfer finished with error 0x%02x "
"detected by MP driver\n",
channel,
trans_buf_p -> mp_error_code & 0xff
);
}
}
}
if ( /*bp != NULL*/ uio_p != NULL || drv_buf_p != NULL ) {
mckk_set_dma_trans_results(state, channel, trans_buf_p, transfer_spec, -1);
if ( !transfer_spec -> async_trans )
(/*bp != NULL*/ uio_p != NULL) ? /*biodone(bp)*/ :
mckk_drv_buf_io_done(state, trans_buf_p, mutex_locked);
}
ME90_LOG(state, ME90_DL_TRACE,
"%s(): I/O transfer successed for channel %d\n", __func__,
channel
);
}
/*
* Terminate transfer on buf - block I/O data transfer structure or
* driver private buffer
*/
/*ARGSUSED*/
static void
mckk_finish_trans(
mcb_state_t *state,
int channel,
me90drv_trans_buf_t *trans_buf_p,
int mutex_locked,
int trans_canceled)
{
me90drv_chnl_state_t *channel_state = NULL;
me90drv_trans_spec_t *transfer_spec_p = NULL;
int async_trans_flag = 0;
#ifdef __BLOCK_BUFFER_USE__
int drv_buf_used = 0;
#endif /* __BLOCK_BUFFER_USE__ */
ME90_LOG(state, ME90_DL_TRACE,
"mckk_finish_trans started for channel %d\n", channel);
channel_state = &state -> all_channels_state[channel];
#ifdef __BLOCK_BUFFER_USE__
drv_buf_used = trans_buf_p -> trans_buf_desc.drv_buf_used;
if (drv_buf_used) {
if (trans_buf_p -> drv_buf_p == NULL) {
ME90_LOG(state, ME90_DL_ERROR,
"mckk_finish_trans drv buffer is NULL in"
" trans buf 0x%08x\n", trans_buf_p);
return;
}
transfer_spec_p = (me90drv_trans_spec_t *)
trans_buf_p -> drv_buf_p -> transfer_spec;
} else {
/* transfer_spec_p = trans_buf_p -> trans_buf_desc.bp -> b_private;*/
transfer_spec_p = trans_buf_p -> trans_buf_desc.uio_p -> transfer_spec;
}
#else
transfer_spec_p = (me90drv_trans_spec_t *) trans_buf_p -> transfer_spec;
#endif /* __BLOCK_BUFFER_USE__ */
async_trans_flag = transfer_spec_p -> async_trans;
me90drv_finish_dma_engine(state, channel, trans_buf_p, mutex_locked);
if (async_trans_flag && !trans_canceled) {
if (!mutex_locked)
{
mutex_enter(&state->mutex); /* start MUTEX */
}
trans_buf_p -> next_trans_buf = NULL;
if (channel_state -> ready_atrans_start == NULL)
channel_state -> ready_atrans_start = trans_buf_p;
else
channel_state -> ready_atrans_end -> next_trans_buf =
trans_buf_p;
channel_state -> ready_atrans_end = trans_buf_p;
channel_state -> ready_atrans_size ++;
cv_broadcast(&state -> atrans_end_cv);
if (!mutex_locked)
{
mutex_exit(&state->mutex); /* end MUTEX */
}
}
#ifdef __BLOCK_BUFFER_USE__
else if (!drv_buf_used)
me90drv_delete_trans_header(state, trans_buf_p);
#endif /* __BLOCK_BUFFER_USE__ */
ME90_LOG(state, ME90_DL_TRACE,
"mckk_finish_trans finished for channel %d\n", channel);
}
/*
* Finish the DMA data transfer endgine on error.
* mutex_enter must be done by caller
*/
/*ARGSUSED*/
static int
mckk_finish_dma_engine_on_error(
mcb_state_t *state,
int channel,
me90drv_rd_reg_t gen_reg_state,
int error_code)
{
me90drv_chnl_state_t *channel_state = NULL;
me90drv_trans_buf_t *trans_buf_p = NULL;
int transfer_size = 0;
int source_size = 0;
int transfer_complited = 0;
me90drv_rd_reg_t board_state = gen_reg_state;
me90drv_wr_reg_t error_reset;
me90drv_drv_intercom_t *drv_communication = NULL;
#ifdef _MP_TIME_USE_
u_int trans_abort_time = 0;
#else
hrtime_t trans_abort_time = ddi_gethrtime();
#endif /* _MP_TIME_USE_ */
drv_communication =
(me90drv_drv_intercom_t *) &state -> ME90DRV_INTERDRV_COMN_AREA;
#ifdef _MP_TIME_USE_
READ_MP_TIME(trans_abort_time);
#endif /* _MP_TIME_USE_ */
channel_state = &state -> all_channels_state[channel];
ME90_LOG(state, ME90_DL_TRACE,
"mckk_finish_dma_engine_on_error started for channel %d\n",
channel);
trans_buf_p = channel_state -> in_progress_start;
if (trans_buf_p == NULL) {
ME90_LOG(state, ME90_DL_ERROR,
"mckk_finish_dma_engine_on_error no transfer in "
"progress for channel %d\n", channel);
return 0;
}
source_size = trans_buf_p -> trans_size;
trans_buf_p -> real_trans_size = transfer_size;
if (board_state.ME90DRV_RGEN_read == 0) {
board_state.ME90DRV_RGEN_read =
state -> ME90DRV_CNTR_ST_REGS -> ME90DRV_RGENS_read;
if (board_state.ME90DRV_RGEN_RERR_read != 0) {
error_reset.ME90DRV_RGEN_write = 0;
state -> ME90DRV_CNTR_ST_REGS -> ME90DRV_RERR_write =
error_reset.ME90DRV_RGEN_RERR_get_to_write;
}
}
if (error_code == ETIME && transfer_complited) {
ME90_LOG(state, ME90_DL_ERROR,
"mckk_finish_dma_engine_on_error transfer with timer "
"expired is complited for channel %d\n", channel);
trans_buf_p -> sparc_error_code = 0;
}
else if (trans_buf_p -> sparc_error_code == 0)
trans_buf_p -> sparc_error_code = error_code;
if (error_code == 0 && trans_buf_p -> sparc_error_code == 0 &&
board_state.ME90DRV_RGEN_RERR_read != 0)
trans_buf_p -> sparc_error_code = EIO;
trans_buf_p -> gen_reg_state = board_state;
trans_buf_p -> intr_transfer_end = trans_abort_time;
me90drv_handle_trans_finish(state,channel, NULL, board_state,
trans_abort_time, 1); /* transfer aborted */
ME90_LOG(state, ME90_DL_TRACE,
"mckk_finish_dma_engine_on_error I/O transfer finished"
" for channel %d\n", channel);
return (trans_buf_p -> sparc_error_code);
}
/*
* Processes list of terminated DMA transfers
*/
/*ARGSUSED*/
static void
mckk_terminate_dma_trans(
mcb_state_t *state,
int channel)
{
me90drv_chnl_state_t *channel_state = NULL;
me90drv_trans_buf_t *cur_trans_buf_p = NULL;
ME90_LOG(state, ME90_DL_TRACE,
"mckk_terminate_dma_trans started for channel %d\n", channel);
channel_state = &state -> all_channels_state[channel];
mutex_enter(&state->mutex); /* start MUTEX */
if (channel_state -> term_trans_processed ||
channel_state -> completed_trans_start == NULL) {
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_TRACE,
"mckk_terminate_dma_trans no transfers to terminate for"
" channel %d\n", channel);
return;
}
channel_state -> term_trans_processed = 1;
mutex_exit(&state->mutex); /* end MUTEX */
while (1) {
mutex_enter(&state->mutex); /* start MUTEX */
cur_trans_buf_p = channel_state -> completed_trans_start;
if (cur_trans_buf_p == NULL) {
channel_state -> completed_trans_end = NULL;
break;
}
channel_state -> completed_trans_size --;
channel_state -> completed_trans_start =
cur_trans_buf_p -> next_trans_buf;
mutex_exit(&state->mutex); /* end MUTEX */
#ifdef __BLOCK_BUFFER_USE__
if (!cur_trans_buf_p -> trans_buf_desc.drv_buf_used ||
(cur_trans_buf_p -> trans_buf_desc.drv_buf_used &&
cur_trans_buf_p -> drv_buf_p != NULL))
#endif /* __BLOCK_BUFFER_USE__ */
mckk_finish_trans(state, channel, cur_trans_buf_p, 0, 0);
#ifdef __BLOCK_BUFFER_USE__
else {
ME90_LOG(state, ME90_DL_ERROR,
"mckk_terminate_dma_trans unknown transfer "
"method for channel %d\n", channel);
}
#endif /* __BLOCK_BUFFER_USE__ */
}
channel_state -> term_trans_processed = 0;
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_TRACE,
"state_terminate_dma_trans successed for channel %d\n", channel);
}
/*
* Delete timeout (mutex_enter must be done by caller)
*/
/*ARGSUSED*/
static void
mckk_delete_timeout(
mcb_state_t *state,
int channel)
{
me90drv_chnl_state_t * channel_state = NULL;
if (channel < 0) {
ME90_LOG(state, ME90_DL_TRACE,
"mckk_delete_timeout general timeout\n");
} else {
ME90_LOG(state, ME90_DL_TRACE,
"mckk_delete_timeout for channel %d\n", channel);
}
if (channel < 0) { /* general timeout */
if (state -> timeout_type == no_timeout_type) {
ME90_LOG(state, ME90_DL_ERROR,
"mckk_delete_timeout : no general timeout\n");
}
state -> timeout_type = no_timeout_type;
state -> timeout_rem = 0;
} else {
channel_state = &state -> all_channels_state[channel];
if (channel_state -> timeout_type == no_timeout_type) {
ME90_LOG(state, ME90_DL_ERROR,
"mckk_delete_timeout : no timeout for"
" channel %d\n", channel);
return;
}
if ((!channel_state -> busy &&
!(state -> drv_general_modes & MULTI_REQ_CHANNEL_DRV_MODE)) ||
(!channel_state -> busy &&
channel_state -> in_progress_start == NULL &&
(state -> drv_general_modes & MULTI_REQ_CHANNEL_DRV_MODE))) {
ME90_LOG(state, ME90_DL_ERROR,
"mckk_delete_timeout : channel %d is not busy"
" by I/O\n", channel);
}
channel_state -> timeout_type = no_timeout_type;
channel_state -> timeout_rem = 0;
}
state -> timeouts_num --;
ME90_LOG(state, ME90_DL_TRACE, "mckk_delete_timeout successed\n");
}
/*
* The channel command timeout recovery. mutex_enter must be done by caller
*/
static void
mckk_general_timeout(mcb_state_t *state)
{
ME90_LOG(state, ME90_DL_TRACE, "mckk_general_timeout unused so far\n");
}
/*
* Reset timeout
*/
/*ARGSUSED*/
static void
mckk_reset_timeout(
mcb_state_t *state,
int channel)
{
if (channel < 0) {
ME90_LOG(state, ME90_DL_TRACE,
"mckk_reset_timeout general timeout\n");
} else {
ME90_LOG(state, ME90_DL_TRACE,
"mckk_reset_timeout for channel %d\n", channel);
}
mutex_enter(&state->mutex); /* start MUTEX */
mckk_delete_timeout(state, channel);
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_TRACE, "mckk_reset_timeout successed\n");
}
/*
* Delete all transfers from list of transfers currently in the progress.
* mutex may be locked by caller
*/
/*ARGSUSED*/
static void
mckk_delete_trans_in_progress(
mcb_state_t *state,
int channel,
int error_code,
int waiting_loop_num,
int mutex_locked)
{
me90drv_chnl_state_t *channel_state = NULL;
me90drv_trans_buf_t *cur_trans_buf_p = NULL;
me90drv_rd_reg_t gen_reg_state;
int cur_loop = 0;
ME90_LOG(state, ME90_DL_TRACE,
"mckk_delete_trans_in_progress started for channel %d\n",
channel);
channel_state = &state -> all_channels_state[channel];
gen_reg_state.ME90DRV_RGEN_read = 0;
if (!mutex_locked)
{
mutex_enter(&state->mutex); /* start MUTEX */
}
while (channel_state -> in_progress_start != NULL) {
cur_trans_buf_p = channel_state -> in_progress_start;
if (cur_trans_buf_p == NULL)
break;
if (!mutex_locked)
{
mutex_exit(&state->mutex); /* end of MUTEX */
}
for (cur_loop = 0; cur_loop < waiting_loop_num; cur_loop ++) {
if (channel_state -> in_progress_start !=
cur_trans_buf_p) {
break;
}
}
if (!mutex_locked)
{
mutex_enter(&state->mutex); /* start MUTEX */
}
if (cur_trans_buf_p != channel_state -> in_progress_start)
continue;
mckk_finish_dma_engine_on_error(state, channel, gen_reg_state,
error_code);
}
if (!mutex_locked)
{
mutex_exit(&state->mutex); /* end of MUTEX */
}
ME90_LOG(state, ME90_DL_TRACE,
"mckk_delete_trans_in_progress finished for channel %d\n",
channel);
}
/*
* Delete all currently executed transfers from list of waiting for start and
* list of transfers in progress.
* mutex may be locked by caller
*/
/*ARGSUSED*/
static void
mckk_delete_all_exec_trans(
mcb_state_t *state,
int channel,
int error_code,
int waiting_loop_num,
int mutex_locked)
{
me90drv_chnl_state_t *channel_state = NULL;
me90drv_trans_buf_t *cur_trans_buf_p = NULL;
#ifdef _MP_TIME_USE_
u_int trans_delete_time = 0;
#else
hrtime_t trans_delete_time = ddi_gethrtime();
#endif /* _MP_TIME_USE_ */
me90drv_drv_intercom_t *drv_communication = NULL;
drv_communication =
(me90drv_drv_intercom_t *) &state -> ME90DRV_INTERDRV_COMN_AREA;
ME90_LOG(state, ME90_DL_TRACE,
"mckk_delete_all_exec_trans started for channel %d\n", channel);
channel_state = &state -> all_channels_state[channel];
mckk_delete_trans_in_progress(state, channel, error_code,
waiting_loop_num, mutex_locked);
while (1) {
if (cur_trans_buf_p == NULL) {
if (!mutex_locked)
{
mutex_enter(&state->mutex); /* start MUTEX */
}
cur_trans_buf_p = channel_state -> wait_list_start;
if (cur_trans_buf_p == NULL) {
channel_state -> wait_list_end = NULL;
if (!mutex_locked)
{
mutex_exit(&state->mutex); /* MUTEX */
}
break;
}
channel_state -> wait_list_size --;
channel_state -> wait_list_start =
cur_trans_buf_p -> next_trans_buf;
if (!mutex_locked)
{
mutex_exit(&state->mutex); /* end of MUTEX */
}
}
#ifdef _MP_TIME_USE_
READ_MP_TIME(trans_delete_time);
#else
trans_delete_time = ddi_gethrtime();
#endif /* _MP_TIME_USE_ */
cur_trans_buf_p -> intr_transfer_end = trans_delete_time;
#ifdef __BLOCK_BUFFER_USE__
if (!cur_trans_buf_p -> trans_buf_desc.drv_buf_used ||
(cur_trans_buf_p -> trans_buf_desc.drv_buf_used &&
cur_trans_buf_p -> drv_buf_p != NULL)) {
#endif /* __BLOCK_BUFFER_USE__ */
cur_trans_buf_p -> sparc_error_code = error_code;
mckk_finish_trans(state, channel, cur_trans_buf_p,
mutex_locked, 0);
#ifdef __BLOCK_BUFFER_USE__
}
else {
ME90_LOG(state, ME90_DL_ERROR,
"mckk_delete_all_exec_trans unknown transfer "
"method for channel %d\n", channel);
}
#endif /* __BLOCK_BUFFER_USE__ */
cur_trans_buf_p = NULL;
}
channel_state -> busy = 0;
ME90_LOG(state, ME90_DL_TRACE,
"mckk_delete_all_exec_trans succeeded for channel %d\n",
channel);
}
/*
* The channel command timeout recovery
*/
static int
mckk_channel_timeout(
mcb_state_t *state,
int channel)
{
me90drv_chnl_state_t *channel_state = NULL;
me90drv_rd_reg_t gen_reg_state;
int rval = 0;
int abort_rval = 0;
ME90_LOG(state, ME90_DL_TRACE,
"mckk_channel_timeout started for channel %d\n", channel);
channel_state = &state -> all_channels_state[channel];
mutex_enter(&state->mutex); /* start MUTEX */
if ((!channel_state -> busy &&
!(state -> drv_general_modes & MULTI_REQ_CHANNEL_DRV_MODE)) ||
(!channel_state -> busy &&
channel_state -> in_progress_start == NULL &&
(state -> drv_general_modes & MULTI_REQ_CHANNEL_DRV_MODE))) {
mutex_exit(&state->mutex); /* end MUTEX */
if (channel_state -> timeout_type != no_timeout_type ||
channel_state -> timeout_rem > 0) {
ME90_LOG(state, ME90_DL_ERROR,
"mckk_channel_timeout: channel %d is free,"
" but timeout is set\n", channel);
mckk_reset_timeout(state,channel);
}
ME90_LOG(state, ME90_DL_TRACE,
"mckk_channel_timeout channel %d : transfer completed"
" already\n", channel);
return 0;
}
if (channel_state -> busy && channel_state -> dma_intr_handled) {
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_TRACE,
"mckk_channel_timeout channel %d : transfer now"
" completed\n", channel);
return 0; /* interrupt handler deletes timeout */
}
if (channel_state -> timeout_type == no_timeout_type) {
ME90_LOG(state, ME90_DL_ERROR,
"mckk_channel_timeout: channel %d is busy, but "
"timeout does not set\n", channel);
} else if (channel_state -> timeout_rem > 0) {
ME90_LOG(state, ME90_DL_ERROR,
"mckk_channel_timeout: channel %d remainder time %d"
" (> 0)\n", channel,channel_state -> timeout_rem);
}
if (channel_state -> in_progress_start == NULL) {
mutex_exit(&state->mutex); /* end MUTEX */
mckk_reset_timeout(state,channel);
return 0;
}
if (channel_state -> in_progress_start -> sparc_error_code == 0) {
channel_state -> in_progress_start -> sparc_error_code = ETIME;
mutex_exit(&state->mutex); /* end MUTEX */
abort_rval = me90drv_abort_dma_transfer(state,channel);
if (abort_rval == 0)
return 0;
mutex_enter(&state->mutex); /* start MUTEX */
}
if (channel_state -> in_progress_start == NULL) {
mutex_exit(&state->mutex); /* end MUTEX */
return 0;
}
gen_reg_state.ME90DRV_RGEN_read = 0;
rval = mckk_finish_dma_engine_on_error(state, channel, gen_reg_state,
ETIME);
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_TRACE,
"mckk_channel_timeout finished for channel %d\n", channel);
return 1;
}
static void mckk_watchdog(caddr_t arg);
/*
* Timeout (watchdog services) callback function
*/
/*ARGSUSED*/
//int
static void
mckk_watchdog_handler(struct work_struct *work)
{
mcb_state_t *state =
container_of(work, mcb_state_t, watchdog_tqueue);
me90drv_chnl_state_t *channel_state = NULL;
int cur_chnl = 0;
#if 0
daemonize("mckk_watchdogd");
do
{
waiting_mode:
ME90_LOG(state, ME90_DL_TRACE, "MCKK: waiting for mckk_watchdog started !!!!\n");
current->policy = SCHED_FIFO;
interruptible_sleep_on(&state->mckk_watchdog_handler);
if (state->waking_up_mckk_watchdog_handler == 1){
ME90_LOG(state, ME90_DL_TRACE, "waking up mckk_watchdog_handler !!!\n");
state->waking_up_mckk_watchdog_handler = 0;
del_timer_sync(&(state -> timeout_idnt));
break;
}
if (state->mckk_watchdog_handler_shutdown == 1) {
ME90_LOG(state, ME90_DL_TRACE, "MCKK: mckk_watchdog_handler exit by signal\n");
state->mckk_watchdog_handler_shutdown = 0;
return 0;
}
} while (1);
#endif
ME90_LOG(state, ME90_DL_TRACE, "mckk_watchdog_handler started\n");
mutex_enter(&state->mutex); /* start MUTEX */
if (state -> timeout_type != no_timeout_type) { /* general timeout */
if (state -> timeouts_num == 0) {
ME90_LOG(state, ME90_DL_ERROR,
"state_watchdog_handler : not handled general "
"timeout, bat timeouts num is 0\n");
}
state -> timeout_rem -= ME90DRV_WATCHDOG_DEF_VALUE;
if (state -> timeout_rem <= 0) /* time is over */
mckk_general_timeout(state);
}
for (cur_chnl = 0; cur_chnl < MAX_ME90DRV_BOARD_CHANNEL_NUM;
cur_chnl ++) {
channel_state = &state -> all_channels_state[cur_chnl];
if (channel_state -> timeout_type != no_timeout_type) {
if (state -> timeouts_num == 0) {
ME90_LOG(state, ME90_DL_ERROR,
"mckk_watchdog_handler : not handled chanel "
"%d timeout, bat timeouts num is 0\n",
cur_chnl);
}
channel_state -> timeout_rem -=
ME90DRV_WATCHDOG_DEF_VALUE;
ME90_LOG(state, ME90_DL_TRACE,
"mckk_watchdog_handler : chanel %d timeout rem = %d\n",
cur_chnl, channel_state -> timeout_rem);
if (channel_state -> timeout_rem <= 0) {
/* time is over */
mutex_exit(&state->mutex); /* end MUTEX */
if (mckk_channel_timeout(state,cur_chnl) != 0) {
mckk_terminate_dma_trans(state,cur_chnl);
me90drv_start_new_trans(state,
cur_chnl);
}
mutex_enter(&state->mutex); /* start MUTEX */
}
}
}
if (state -> timeouts_num > 0) { /* watchdog services are needed */
/*state -> timeout_idnt = timeout(state_watchdog,
(caddr_t) state,
drv_usectohz(
(clock_t)ME90DRV_WATCHDOG_DEF_VALUE));*/
struct timer_list *tm = &(state -> timeout_idnt);
tm->expires = jiffies + drv_usectohz(ME90DRV_WATCHDOG_DEF_VALUE);
tm->function = (void *)mckk_watchdog;
tm->data = (unsigned long)state;
mutex_exit(&state->mutex); /* end MUTEX */
add_timer(tm);
// mutex_exit(&state->mutex); /* end MUTEX */
} else {
state -> timeouts_num = 0;
state -> timeout_idnt.expires = 0;
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_TRACE,
"mckk_watchdog_handler services finished\n");
}
// goto waiting_mode;
}
static void mckk_watchdog(caddr_t arg)
{
mcb_state_t *state = (mcb_state_t *) arg;
ME90_LOG(state, ME90_DL_TRACE, "MCKK: mckk_watchdog start\n");
// state->waking_up_mckk_watchdog_handler = 1;
// wake_up(&state->mckk_watchdog_handler);
schedule_work(&state->watchdog_tqueue);
ME90_LOG(state, ME90_DL_TRACE, "MCKK: mckk_watchdog finish\n");
}
/*
* Set timeouts watchdog services startup if need
*/
/*ARGSUSED*/
static int
mckk_set_timeout(
mcb_state_t *state,
timeout_type_t timeout_type,
timeout_value_t timeout_value_arg,
int channel,
int mutex_started)
{
timeout_value_t timeout_value = timeout_value_arg;
me90drv_chnl_state_t *channel_state = NULL;
int start_timeout = 0;
int timeout_exist = 0;
if (channel < 0) {
ME90_LOG(state, ME90_DL_TRACE,
"mckk_set_timeout general timeout: type %d value %d\n",
(int)timeout_type, (int)timeout_value);
} else {
ME90_LOG(state, ME90_DL_TRACE,
"mckk_set_timeout for channel %d type %d value %d\n",
channel,(int)timeout_type, (int)timeout_value);
}
if (timeout_value <= 0) {
switch (timeout_type) {
case read_timeout_type :
timeout_value = (10 * ME90DRV_READ_TIMEOUT_DEF_VALUE);
break;
case write_timeout_type :
timeout_value = (10 * ME90DRV_WRITE_TIMEOUT_DEF_VALUE);
break;
case batch_timeout_type :
timeout_value = ME90DRV_BATCH_TIMEOUT_DEF_VALUE;
break;
case terminate_timeout_type :
timeout_value =
ME90DRV_TERMINATE_TIMEOUT_DEF_VALUE;
break;
case no_timeout_type :
default :
ME90_LOG(state, ME90_DL_ERROR,
"mckk_set_timeout failed : undefined"
" timeout type %d\n", timeout_type);
return 1;
}
}
if (!mutex_started)
{
mutex_enter(&state->mutex); /* start MUTEX */
}
if (channel < 0) { /* general timeout */
if (state -> timeout_type != no_timeout_type ||
state -> timeout_rem > 0) {
if (!mutex_started)
{
mutex_exit(&state->mutex); /* end MUTEX */
}
ME90_LOG(state, ME90_DL_ERROR,
"mckk_set_timeout failed : general"
" timeout exists already\n");
return 1;
}
state -> timeout_type = timeout_type;
state -> timeout_rem = timeout_value;
} else {
channel_state = &state -> all_channels_state[channel];
if (channel_state -> timeout_type != no_timeout_type ||
channel_state -> timeout_rem > 0) {
int rval = 0;
ME90_LOG(state, ME90_DL_ERROR,
"mckk_set_timeout failed : channel %d timeout "
"exists already type %d =? %d =? %d\n",
channel, timeout_type, state -> timeout_type,
terminate_timeout_type);
rval = 1;
if (!mutex_started)
{
mutex_exit(&state->mutex); /* end MUTEX */
}
return rval;
}
if ((!channel_state -> busy &&
!(state -> drv_general_modes & MULTI_REQ_CHANNEL_DRV_MODE)) ||
(!channel_state -> busy &&
channel_state -> in_progress_start == NULL &&
(state -> drv_general_modes & MULTI_REQ_CHANNEL_DRV_MODE))) {
if (!mutex_started)
{
mutex_exit(&state->mutex); /* end MUTEX */
}
ME90_LOG(state, ME90_DL_ERROR,
"mckk_set_timeout failed : channel %d is not"
" busy by I/O cmd\n", channel);
return 1;
}
channel_state -> timeout_type = timeout_type;
channel_state -> timeout_rem = timeout_value;
channel_state -> last_timeout_type = timeout_type;
channel_state -> last_timeout_value = timeout_value;
}
ME90_LOG(state, ME90_DL_TRACE,
"mckk_set_timeout: channel_state -> timeout_type = %d\n",
(int)channel_state -> timeout_type);
ME90_LOG(state, ME90_DL_TRACE,
"mckk_set_timeout: channel_state -> timeout_rem = %d\n",
(int)channel_state -> timeout_rem);
ME90_LOG(state, ME90_DL_TRACE,
"mckk_set_timeout: channel_state -> last_timeout_type = %d\n",
(int)channel_state -> last_timeout_type);
ME90_LOG(state, ME90_DL_TRACE,
"mckk_set_timeout: channel_state -> last_timeout_value = %d\n",
(int)channel_state -> last_timeout_value);
if (state -> timeouts_num == 0) { /* start timeouting as watch */
/* dog services */
/* if (state -> timeout_idnt == 0) {
state -> timeout_idnt = timeout(state_watchdog,
(caddr_t) state,
drv_usectohz(
(clock_t)ME90DRV_WATCHDOG_DEF_VALUE));*/
if (state -> timeout_idnt.expires == 0) {
struct timer_list *tm = &state -> timeout_idnt;
init_timer(tm);
tm->expires = jiffies + drv_usectohz(ME90DRV_WATCHDOG_DEF_VALUE);
tm->function = (void *)mckk_watchdog;
tm->data = (unsigned long)state;
add_timer(tm);
if (state -> timeout_idnt.expires == 0) {
if (!mutex_started)
{
mutex_exit(&state->mutex);
}
ME90_LOG(state, ME90_DL_ERROR,
"mckk_set_timeout: timeout call"
" failed\n");
return 1;
}
start_timeout = 1;
} else
timeout_exist = 1;
}
state -> timeouts_num ++;
if (!mutex_started)
{
mutex_exit(&state->mutex); /* end MUTEX */
}
if (start_timeout) {
ME90_LOG(state, ME90_DL_TRACE,
"mckk_set_timeout : watchdog started for a time %d"
" mks\n", ME90DRV_WATCHDOG_DEF_VALUE);
} else if (timeout_exist) {
ME90_LOG(state, ME90_DL_TRACE,
"mckk_set_timeout : watchdog was been started "
"already\n");
}
ME90_LOG(state, ME90_DL_TRACE, "mckk_set_timeout successed\n");
return 0;
}
/*
* Set timeout for channel current transfer in progress,
*/
/*ARGSUSED*/
static void
mckk_set_trans_timeout(
mcb_state_t *state,
int channel,
int mutex_started)
{
me90drv_chnl_state_t *channel_state = NULL;
me90drv_trans_buf_t *cur_trans_buf = NULL;
me90drv_trans_spec_t *transfer_spec_p = NULL;
timeout_type_t timeout_type = no_timeout_type;
timeout_value_t timeout_value = 0;
#ifdef __BLOCK_BUFFER_USE__
/* buf_t *bp = NULL;*/
uio_t *uio_p = NULL;
#endif /* __BLOCK_BUFFER_USE__ */
dbgmckk("mckk_set_trans_timeout started for channel %d\n", channel);
udelay(10000);
channel_state = &state -> all_channels_state[channel];
if (!mutex_started){
mutex_enter(&state->mutex); /* start MUTEX */
}
cur_trans_buf = channel_state -> in_progress_start;
if (cur_trans_buf == NULL) {
if (!mutex_started)
{
mutex_exit(&state->mutex); /* end MUTEX */
}
ME90_LOG(state, ME90_DL_TRACE,
"mckk_set_trans_timeout no any transfer in progress for"
" channel %d\n", channel);
return;
}
if (channel_state -> timeout_type != no_timeout_type ||
channel_state -> timeout_rem > 0) {
if (!mutex_started)
{
mutex_exit(&state->mutex); /* end MUTEX */
}
ME90_LOG(state, ME90_DL_TRACE,
"mckk_set_trans_timeout timeout is set already for"
" channel %d\n", channel);
return;
}
#ifdef __BLOCK_BUFFER_USE__
if (cur_trans_buf -> trans_buf_desc.drv_buf_used) {
if (cur_trans_buf -> drv_buf_p != NULL) {
transfer_spec_p = (me90drv_trans_spec_t *)
cur_trans_buf -> drv_buf_p -> transfer_spec;
}
} else {
/* bp = cur_trans_buf -> trans_buf_desc.bp;
transfer_spec_p = bp -> b_private; */
uio_p = cur_trans_buf -> trans_buf_desc.uio_p;
transfer_spec_p = uio_p -> transfer_spec;
}
#else /* ! __BLOCK_BUFFER_USE__ && ! __TRANS_SPEC_INTO_BUF__ */
transfer_spec_p =
(me90drv_trans_spec_t *)cur_trans_buf -> transfer_spec;
#endif /* __BLOCK_BUFFER_USE__ */
if (transfer_spec_p != NULL) {
if (transfer_spec_p -> read_write_flag & B_READ)
timeout_type = read_timeout_type;
else
timeout_type = write_timeout_type;
timeout_value = transfer_spec_p -> timer_interval;
} else
timeout_type = read_timeout_type;
mckk_set_timeout(state, timeout_type, timeout_value, channel, 1);
if (!mutex_started)
{
mutex_exit(&state->mutex); /* end MUTEX */
}
dbgmckk("mckk_set_trans_timeout finished for channel %d\n", channel);
}
/*ARGSUSED*/
static int
mckk_set_transfer_done(
mcb_state_t *state,
int channel,
trans_state_t transfer_state)
{
me90drv_chnl_state_t *channel_state = NULL;
ME90_LOG(state, ME90_DL_TRACE,
"mckk_set_transfer_done for channel %d started\n", channel);
channel_state = &state -> all_channels_state[channel];
/*
* unblock any threads waiting the channel freeing
*/
channel_state -> transfer_state = transfer_state;
channel_state -> busy = 0;
cv_broadcast(&state -> channel_cv);
ME90_LOG(state, ME90_DL_TRACE,
"mckk_set_transfer_done for channel %d successed\n", channel);
return (0);
}
/*
* Terminate current streaming transfer and launch next transfer as
* current
*/
/*ARGSUSED*/
static void
mcb_handle_trans_finish(
mcb_state_t *state,
int channel,
trans_result_t *trans_results,
mc_rd_reg_t gen_reg_state,
#ifdef _MP_TIME_USE_
u_int intr_transfer_end,
#else
hrtime_t intr_transfer_end,
#endif /* _MP_TIME_USE_ */
int trans_aborted)
{
me90drv_chnl_state_t *channel_state = NULL;
trans_buf_t *cur_trans_buf = NULL;
ME90_LOG(state, ME90_DL_TRACE,
"mckk_handle_trans_finish started for channel %d\n", channel);
channel_state = &state -> all_channels_state[channel];
cur_trans_buf = channel_state -> in_progress_start;
if (cur_trans_buf == NULL) {
ME90_LOG(state, ME90_DL_ERROR,
"mckk_handle_trans_finish no any transfer in progress"
" for channel %d\n", channel);
return;
}
if (trans_results != NULL) {
cur_trans_buf -> real_trans_size =
trans_results -> real_size;
cur_trans_buf -> mp_error_code = trans_results -> mp_error_code;
cur_trans_buf -> board_state_byte = trans_results -> state_byte;
cur_trans_buf -> sp_state_byte = 0;
cur_trans_buf -> gen_reg_state = gen_reg_state;
cur_trans_buf -> intr_transfer_end = intr_transfer_end;
}
mckk_delete_timeout(state,channel);
channel_state -> in_progress_start = cur_trans_buf -> next_trans_buf;
if (channel_state -> in_progress_start == NULL) {
channel_state -> in_progress_end = NULL;
}
channel_state -> in_progress_size --;
cur_trans_buf -> next_trans_buf = NULL;
if (channel_state -> completed_trans_start == NULL)
channel_state -> completed_trans_start = cur_trans_buf;
else
channel_state -> completed_trans_end -> next_trans_buf =
cur_trans_buf;
channel_state -> completed_trans_end = cur_trans_buf;
channel_state -> completed_trans_size ++;
if (channel_state -> in_progress_start == NULL)
channel_state -> in_progress = 0;
if (channel_state -> in_progress_start != NULL) {
if (!channel_state -> streaming)
mckk_set_trans_timeout(state, channel, 1);
else if (channel_state -> pseudostreaming &&
!channel_state -> in_progress_start -> pseudobuf)
mckk_set_trans_timeout(state, channel, 1);
}
if (!(state -> drv_general_modes & MULTI_REQ_CHANNEL_DRV_MODE) &&
!channel_state -> streaming)
mckk_set_transfer_done(state, channel, completed_trans_state);
else {
cv_broadcast(&state -> channel_cv);
}
ME90_LOG(state, ME90_DL_TRACE,
"mckk_handle_trans_finish successed for channel %d\n", channel);
}
/*
* Clean base memory of board
*/
/*ARGSUSED*/
static void
me90_clean_base_memory(mcb_state_t *state)
{
u_int *base_memory = NULL;
int cur_word = 0;
ME90_LOG(state, ME90_DL_TRACE, "mckk_clean_base_memory started\n");
base_memory = (u_int *) state -> ME90DRV_BMEM;
for (cur_word = 0; cur_word < (ME90DRV_BMEM_REG_SET_LEN +
(sizeof(u_int)-1))/sizeof(u_int);
cur_word ++) {
base_memory[cur_word] = ME90DRV_MP_HALT_OPCODE;
}
state -> mp_drv_loaded = 0;
ME90_LOG(state, ME90_DL_TRACE, "mckk_clean_base_memory finished\n");
}
/*
* Clean interdriver communication area
*/
/*ARGSUSED*/
static void
mckk_clean_drv_communication(me90drv_state_t *state)
{
me90drv_drv_intercom_t *drv_communication = NULL;
int cur_arg = 0;
ME90_LOG(state, ME90_DL_TRACE, "mckk_clean_drv_communication started\n");
drv_communication =
(me90drv_drv_intercom_t *) &state -> ME90DRV_INTERDRV_COMN_AREA;
drv_communication -> mp_task = me90drv_no_mp_task;
drv_communication -> sparc_task = me90drv_no_sparc_task;
for (cur_arg = 0; cur_arg < sizeof(drv_communication -> mp_args) /
sizeof(*drv_communication -> mp_args.args_area);
cur_arg ++) {
drv_communication -> mp_args.args_area[cur_arg] = 0;
}
for (cur_arg = 0; cur_arg < sizeof(drv_communication -> sparc_args) /
sizeof(*drv_communication -> sparc_args.args_area);
cur_arg ++) {
drv_communication -> sparc_args.args_area[cur_arg] = 0;
}
ME90_LOG(state, ME90_DL_TRACE,
"mckk_clean_drv_communication successed\n");
}
/*
* First startup and reset of MicroProcessor and its driver
*/
/*ARGSUSED*/
static int
me90_reset_mp(
mcb_state_t *state,
int halt_mp,
int clean_bmem)
{
int rval = 0;
ME90_LOG(state, ME90_DL_TRACE, "mckk_reset_mp started\n");
rval = me90drv_reset_general_regs(state, halt_mp);
if (clean_bmem)
me90_clean_base_memory(state);
mckk_clean_drv_communication(state);
if (rval != 0) {
ME90_LOG(state, ME90_DL_ERROR, "mckk_reset_mp: reset board and MP finished with error\n");
return 1;
} else {
ME90_LOG(state, ME90_DL_TRACE, "mckk_reset_mp: reset board and MP successed\n");
return 0;
}
}
/*
* Copy data from a source kernel address to a MP base memory. Source addresss
* and base memory address must have the same alignment into word
*/
/*ARGSUSED*/
static int mckk_write_base_memory(
mcb_state_t *state,
caddr_t address_from,
caddr_t address_to,
size_t byte_size,
int char_data)
{
u_int * kmem_area_from = NULL;
u_int * bmem_area_to = NULL;
size_t begin_rem = 0;
size_t cur_byte_size = 0;
size_t word_size = 0;
size_t rem = 0;
int cur_word = 0;
ME90_LOG(state, ME90_DL_TRACE,
"mckk_write_base_memory started to copy data from addr 0x%08x"
" to BMEM addr 0x%08x size 0x%x\n",
address_from,address_to,byte_size);
if ((long) address_to < 0 ||
(long) address_to >= MC_BMEM_REG_SET_LEN ||
(long) address_to + byte_size > MC_BMEM_REG_SET_LEN
)
{
ME90_LOG(state, ME90_DL_ERROR,
"mckk_write_base_memory bad address and/or size of BMEM\n"
);
return EINVAL;
}
if (((long) address_from & (sizeof(u_int)-1)) !=
((long) address_to & (sizeof(u_int)-1))
)
{
ME90_LOG(state, ME90_DL_ERROR,
"mckk_write_base_memory kernel and BMEM addresses have "
"different alignment into word\n");
return EINVAL;
}
begin_rem = ((long) address_from & (sizeof(u_int)-1));
kmem_area_from = (u_int *) ((u_long) address_from - begin_rem);
bmem_area_to = (u_int *) & state -> MC_BMEM[(long) address_to - begin_rem];
cur_byte_size = byte_size;
if (begin_rem != 0)
{
u_int first_bmem_word = bmem_area_to[0];
u_char * first_bmem_word_p = (u_char *) & first_bmem_word;
u_char * first_kernel_word = (u_char *) & kmem_area_from[0];
int begin_size = sizeof(u_int) - begin_rem;
int cur_byte = 0;
if (char_data)
first_bmem_word = /*mckk_rotate_word_bytes(*/first_bmem_word/*)*/;
begin_size = (begin_size > cur_byte_size) ? cur_byte_size : begin_size;
for (cur_byte = begin_rem;
cur_byte < begin_rem + begin_size;
cur_byte ++
)
{
first_bmem_word_p[cur_byte] = first_kernel_word[cur_byte];
}
if (char_data)
first_bmem_word = /*mckk_rotate_word_bytes(*/first_bmem_word/*)*/;
bmem_area_to[0] = first_bmem_word;
cur_byte_size -= begin_size;
/*(int)*/ kmem_area_from ++;
/*(int)*/ bmem_area_to ++;
}
word_size = cur_byte_size / sizeof(u_int);
rem = byte_size % sizeof(u_int);
for (cur_word = 0; cur_word < word_size; cur_word ++)
{
if (char_data)
bmem_area_to[cur_word] = /*mckk_rotate_word_bytes(*/
kmem_area_from[cur_word]/*)*/;
else
bmem_area_to[cur_word] = kmem_area_from[cur_word];
}
if (rem != 0)
{
u_int last_bmem_word = bmem_area_to[word_size];
u_char * last_bmem_word_p = (u_char *) & last_bmem_word;
u_char * last_kernel_word = (u_char *) & kmem_area_from[word_size];
int cur_byte = 0;
if (char_data)
last_bmem_word = /*mckk_rotate_word_bytes(*/last_bmem_word/*)*/;
for (cur_byte = 0; cur_byte < rem; cur_byte ++)
{
last_bmem_word_p[cur_byte] = last_kernel_word[cur_byte];
}
if (char_data)
last_bmem_word = /*mckk_rotate_word_bytes(*/last_bmem_word/*)*/;
bmem_area_to[word_size] = last_bmem_word;
}
ME90_LOG(state, ME90_DL_TRACE,
"mckk_write_base_memory succeeded to copy data from addr 0x%08x"
" to BMEM addr 0x%08x size 0x%x\n",
address_from,address_to,byte_size);
return 0;
}
/*
* Restart of MicroProcessor and its driver after hangup, mutex must be locked
* by caller
*/
/*ARGSUSED*/
static int
mckk_restart_mp(
mcb_state_t *state,
int drv_comm_area_locked)
{
int rval = 0;
me90drv_mp_drv_args_t *mp_drv_init_info_p = NULL;
me90drv_sparc_drv_args_t drv_load_results;
u_int rom_drv_init_code[] =
ME90_MP_ROM_DRV_INIT_CODE;
me90_mp_rom_drv_t *mp_rom_drv_init_area = NULL;
ME90_LOG(state, ME90_DL_TRACE, "mckk_restart_mp started\n");
me90_reset_mp(state, 2, 0);
if ((!state -> mp_drv_loaded && state -> mp_debug_drv_flag ) ||
!state -> mp_drv_started) {
ME90_LOG(state, ME90_DL_ERROR,
"mckk_restart_mp: MP driver was not loaded or started"
" up\n");
return 1;
}
if (state -> mp_debug_drv_flag)
rval = mckk_write_base_memory(state,
state -> mp_init_code.mem_address,
state -> mp_init_code.mp_bmem_address,
state -> mp_init_code.byte_size, 1);
else
rval = mckk_write_base_memory(state,
(caddr_t)&rom_drv_init_code,
state -> mp_init_code.mp_bmem_address,
sizeof(rom_drv_init_code), 1);
if (rval != 0) {
ME90_LOG(state, ME90_DL_ERROR,
"mckk_restart_mp failed - write init code in bmem"
" failed\n");
return rval;
}
if (state -> mp_init_code.mp_drv_init_info != NULL &&
state -> mp_init_code.mp_drv_init_info_size > 0)
mp_drv_init_info_p = &state -> mp_drv_init_info;
mp_rom_drv_init_area = (me90_mp_rom_drv_t *)
&state -> ME90DRV_BMEM[ME90_MP_ROM_DRV_INIT_ADDR];
mp_rom_drv_init_area -> debug_drv_start =
state -> mp_debug_drv_flag;
mp_rom_drv_init_area -> rom_disable = 0;
if ((rval = me90drv_submit_mp_task(state, drv_load_mp_task,
mp_drv_init_info_p, 1, NULL, &drv_load_results,
drv_comm_area_locked)) != 0) {
ME90_LOG(state, ME90_DL_ERROR,
"mckk_restart_mp failed - MP driver init errors\n");
return rval;
}
if (drv_load_results.mp_init_results.mp_error_code != 0) {
ME90_LOG(state, ME90_DL_ERROR,
"mckk_restart_mp failed - with error detected by MP"
" driver 0x%02x\n",
drv_load_results.mp_init_results.mp_error_code & 0xff);
return rval;
}
ME90_LOG(state, ME90_DL_TRACE, "mckk_restart_mp successed\n");
return 0;
}
/*
* Restart all synchronous channels: start waiting for execution transfers.
*/
/*ARGSUSED*/
static void
mckk_restart_all_sync_channel(mcb_state_t *state)
{
int cur_chnl = 0;
ME90_LOG(state, ME90_DL_TRACE,
"mckk_restart_all_sync_channel started \n");
for (cur_chnl = 0; cur_chnl < MAX_ME90DRV_BOARD_CHANNEL_NUM;
cur_chnl ++) {
me90drv_start_new_trans(state,cur_chnl);
}
ME90_LOG(state, ME90_DL_TRACE,
"mckk_restart_all_sync_channel finished \n");
}
/*
* Process all terminated transfers in all channels
*/
/*ARGSUSED*/
static void
mckk_terminate_all_dma_trans(mcb_state_t *state)
{
int cur_chnl = 0;
ME90_LOG(state, ME90_DL_TRACE, "mckk_terminate_all_dma_trans started\n");
for (cur_chnl = 0; cur_chnl < MAX_ME90DRV_BOARD_CHANNEL_NUM;
cur_chnl ++)
mckk_terminate_dma_trans(state, cur_chnl);
ME90_LOG(state, ME90_DL_TRACE,
"mckk_terminate_all_dma_trans successed\n");
}
/*
* Retrieve MP and transfers execution after hangup of MP or other errors
* occured in the board.
*/
/*ARGSUSED*/
static int
me90_retrieve_trans_mode(
mcb_state_t *state,
int drv_comm_area_locked,
int unconditional_restsrt,
me90drv_rd_reg_t gen_reg_state)
{
int cur_chnl = 0;
me90drv_chnl_state_t *cur_channel_state = NULL;
int rval = 0;
int retrieve_reason = 0;
int error_code = 0;
ME90_LOG(state,ME90_DL_TRACE, "mckk_retrieve_trans_mode started\n");
mutex_enter(&state->mutex); /* start MUTEX */
if (!drv_comm_area_locked) {
while (state -> drv_comm_busy)
cv_wait_sig(&state -> drv_comm_cv, &state->mutex);
// cv_spin_wait(&state -> drv_comm_cv, &state->lock);
state -> drv_comm_busy = 1;
} else if (!state -> drv_comm_busy)
ME90_LOG(state, ME90_DL_ERROR,
"mckk_retrieve_trans_mode interdriver communication "
"area not locked\n");
retrieve_reason = state -> mp_state;
if (retrieve_reason != hangup_mp_state &&
retrieve_reason != fault_mp_state &&
retrieve_reason != adapter_abend_mp_state &&
!(retrieve_reason == crash_mp_state && unconditional_restsrt)) {
if (!drv_comm_area_locked) {
state -> drv_comm_busy = 0;
cv_broadcast(&state -> drv_comm_cv);
}
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state,ME90_DL_TRACE,
"mckk_retrieve_trans_mode retrieved already\n");
return 0;
} else if ((!(state -> drv_general_modes & RETRIEVE_MP_HANGUP_DRV_MODE) &&
retrieve_reason == hangup_mp_state) ||
(!(state -> drv_general_modes & RETRIEVE_DEV_FAULT_DRV_MODE) &&
retrieve_reason == fault_mp_state) ||
(!(state -> drv_general_modes & RETRIEVE_DEV_FAULT_DRV_MODE) &&
retrieve_reason == adapter_abend_mp_state)) {
if (retrieve_reason == hangup_mp_state)
rval = EMPHANGUP;
else if (retrieve_reason == fault_mp_state)
rval = EDEVFAULT;
else if (retrieve_reason == adapter_abend_mp_state)
rval = EADPTABEND;
else
rval = EIO;
if (!drv_comm_area_locked) {
state -> drv_comm_busy = 0;
cv_broadcast(&state -> drv_comm_cv);
}
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state,ME90_DL_TRACE,
"mckk_retrieve_trans_mode retrieved locked by general "
"driver mode\n");
return rval;
}
ME90_LOG(state,ME90_DL_ERROR,
"retrieve of transfer state started !!!\n");
state -> mp_state = restarted_mp_state;
if (retrieve_reason == hangup_mp_state)
error_code = EMPHANGUP;
else if (retrieve_reason == fault_mp_state)
error_code = EDEVFAULT;
else if (retrieve_reason == adapter_abend_mp_state)
error_code = EADPTABEND;
else if (retrieve_reason == crash_mp_state)
error_code = EMPCRASH;
else {
ME90_LOG(state,ME90_DL_ERROR,
"mckk_retrieve_trans_mode bad MP state\n");
error_code = EMPHANGUP;
}
for (cur_chnl = 0; cur_chnl < MAX_ME90DRV_BOARD_CHANNEL_NUM;
cur_chnl ++) {
cur_channel_state = &state -> all_channels_state[cur_chnl];
while (cur_channel_state -> in_progress_start != NULL) {
mckk_finish_dma_engine_on_error(state, cur_chnl,
gen_reg_state, error_code);
}
}
rval = mckk_restart_mp(state,1);
if (rval != 0) {
state -> mp_state = crash_mp_state;
me90drv_delete_connection_polling(state, EMPCRASH);
if (!drv_comm_area_locked) {
state -> drv_comm_busy = 0;
cv_broadcast(&state -> drv_comm_cv);
}
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state,ME90_DL_ERROR,
"mckk_retrieve_trans_mode cannot restart MP\n");
mckk_restart_all_sync_channel(state);
mckk_terminate_all_dma_trans(state);
return EMPCRASH;
}
rval = me90drv_recover_trans_state(state, 1, 1);
if (rval != 0)
ME90_LOG(state,ME90_DL_ERROR,
"mckk_retrieve_trans_mode cannot recover transfer"
" state\n");
if (!drv_comm_area_locked) {
state -> drv_comm_busy = 0;
cv_broadcast(&state -> drv_comm_cv);
}
mutex_exit(&state->mutex); /* end MUTEX */
mckk_restart_all_sync_channel(state);
mckk_terminate_all_dma_trans(state);
ME90_LOG(state,ME90_DL_ERROR, "mckk_retrieve_trans_mode successed\n");
return rval;
}
/*
* Interrupt MP and waiting MP reaction.
* Mutex must be provided by caller
*/
/*ARGSUSED*/
static int
mckk_interrupt_mp(
mcb_state_t *state,
int mp_restart,
int wait_mp_task_accept,
int wait_mp_rom_drv_disable)
{
volatile me90drv_cntr_st_reg_t *general_regs = NULL;
me90drv_drv_intercom_t *drv_communication = NULL;
me90_mp_rom_drv_t *mp_rom_drv_init_area = NULL;
#ifndef _WITHOUT_MP_INTERRUPT_
me90drv_rd_reg_t cur_regs_value;
me90drv_wr_reg_t intr_set_value;
#endif /* _WITHOUT_MP_INTERRUPT_ */
int waiting_time = 0;
#ifndef _WITHOUT_MP_INTERRUPT_
int intr_processed = 0;
#endif /* _WITHOUT_MP_INTERRUPT_ */
int task_accepted = 0;
int rom_disable = 0;
int cur_tryon = 0;
ME90_LOG(state, ME90_DL_TRACE, "mckk_interrupt_mp started\n");
ME90_LOG(state, ME90_DL_TRACE, "mckk_interrupt_mp: mp_restart = 0x%x\n",
mp_restart);
ME90_LOG(state, ME90_DL_TRACE, "mckk_interrupt_mp: wait_mp_task_accept = 0x%x\n",
wait_mp_task_accept);
ME90_LOG(state, ME90_DL_TRACE, "mckk_interrupt_mp: wait_mp_rom_drv_disable = 0x%x\n",
wait_mp_rom_drv_disable);
general_regs = state -> ME90DRV_CNTR_ST_REGS;
drv_communication =
(me90drv_drv_intercom_t *) &state -> ME90DRV_INTERDRV_COMN_AREA;
if (wait_mp_rom_drv_disable)
mp_rom_drv_init_area = (me90_mp_rom_drv_t *)
&state -> ME90DRV_BMEM[ME90_MP_ROM_DRV_INIT_ADDR];
#ifndef _WITHOUT_MP_INTERRUPT_
me90drv_read_general_regs(general_regs, ME90DRV_TI_reg_type,
&cur_regs_value);
if (cur_regs_value.ME90DRV_RGEN_TI_read == 1) {
/* MP did not processed interrupt */
if (cur_regs_value.ME90DRV_RGEN_TMI_read == 0) {
ME90_LOG(state, ME90_DL_ERROR,
"mckk_interrupt_mp MP interrupt is masked,"
" so not processed\n");
} else {
ME90_LOG(state, ME90_DL_ERROR,
"mckk_interrupt_mp last MP interrupt not"
" processed by MP\n");
}
return EMPHANGUP;
}
if (!mp_restart) {
intr_set_value.ME90DRV_RGEN_RERR_write = 0;
intr_set_value.ME90DRV_RGEN_TI_write = 1;
/* interrupt MP, interrupt mask can be set by MP */
me90drv_write_general_regs(general_regs, ME90DRV_TI_reg_type,
intr_set_value, &cur_regs_value);
/*
* Waiting Loop of interrupt reset by MP driver
*/
waiting_time = 0;
intr_processed = 0;
while (waiting_time < ME90DRV_INTR_RESET_BY_MP_TIME &&
!intr_processed) {
for (cur_tryon = 0;
cur_tryon <= ME90DRV_INTR_RESET_BY_MP_TRYON;
cur_tryon++) {
me90drv_read_general_regs(general_regs,
ME90DRV_TI_reg_type, &cur_regs_value);
if (cur_regs_value.ME90DRV_RGEN_TI_read == 1)
continue;
intr_processed = 1;
break;
}
if (intr_processed)
break;
// Sol in mksec drv_usecwait(TASK_ACCEPT_BY_MP_DELAY_TIME);
/* Lin mksec */ udelay(TASK_ACCEPT_BY_MP_DELAY_TIME);
waiting_time += INTR_RESET_BY_MP_DELAY_TIME;
}
if (!intr_processed) {
ME90_LOG(state, ME90_DL_ERROR,
"mckk_interrupt_mp interrupt not processed "
"by MP for time %d mks + %d try on\n",
waiting_time,cur_tryon);
return EMPHANGUP;
}
ME90_LOG(state, ME90_DL_TRACE,
"mckk_interrupt_mp interrupt was processed by MP for"
" time %d mks + %d try on\n",
waiting_time,cur_tryon);
}
#endif /* _WITHOUT_MP_INTERRUPT_ */
if (mp_restart) {
if (drv_communication -> mp_task == no_mp_task) {
ME90_LOG(state, ME90_DL_ERROR,
"mckk_interrupt_mp MP task is empty already\n");
}
if (me90drv_reset_general_regs(state, 0) != 0) {
ME90_LOG(state, ME90_DL_ERROR,
"mckk_interrupt_mp restart of MP finished"
" with error\n");
}
}
/*
* Waiting Loop of current task field reset by MP driver
*/
if (wait_mp_task_accept || wait_mp_rom_drv_disable) {
waiting_time = 0;
task_accepted = 0;
rom_disable = 0;
while (waiting_time < ME90DRV_TASK_ACCEPT_BY_MP_TIME &&
!task_accepted && !rom_disable) {
for (cur_tryon = 0;
cur_tryon < ME90DRV_TASK_ACCEPT_BY_MP_TRYON;
cur_tryon ++) {
if (drv_communication -> mp_task ==
no_mp_task) {
task_accepted = 1;
break;
} else if (wait_mp_rom_drv_disable) {
if (mp_rom_drv_init_area ->
rom_disable) {
rom_disable = 1;
break;
}
}
}
if (task_accepted || rom_disable)
break;
/* delay(drv_usectohz(ME90DRV_TASK_ACCEPT_BY_MP_DELAY_TIME)); */
// Sol mksec drv_usecwait(ME90DRV_TASK_ACCEPT_BY_MP_DELAY_TIME);
/* Lin mksec */ udelay(ME90DRV_TASK_ACCEPT_BY_MP_DELAY_TIME);
waiting_time += ME90DRV_TASK_ACCEPT_BY_MP_DELAY_TIME;
}
if (rom_disable) {
return EMPROMDISABLE;
} else if (!task_accepted) {
ME90_LOG(state, ME90_DL_ERROR,
"mckk_interrupt_mp Mp did not accept task for"
" time %d mks + %d try on\n",
waiting_time, cur_tryon);
return EMPHANGUP;
}
}
ME90_LOG(state, ME90_DL_TRACE,
"mckk_interrupt_mp MP accepted task for time %d"
" mks + %d try on\n", waiting_time, cur_tryon);
ME90_LOG(state, ME90_DL_TRACE, "mckk_interrupt_mp successed\n");
return 0;
}
/*
* Write MP task arguments into interdriver communication area, submit MP
* to execute the task and waiting MP reaction
*/
/*ARGSUSED*/
static int
submit_mp_task(
mcb_state_t * state,
mp_task_t mp_task,
mp_drv_args_t * task_args,
int mutex_enter_done,
trans_info_t * trans_res_info,
sparc_drv_args_t * mp_task_results,
int restart
)
{
drv_intercom_t *drv_communication = NULL;
int args_num = 0;
int cur_arg = 0;
int channel = 0;
me90drv_chnl_state_t *channel_state = NULL;
#ifndef __WAIT_MP_TASK_ACCEPT__
int waiting_time = 0;
int task_accepted = 0;
int cur_tryon = 0;
#endif /* __WAIT_MP_TASK_ACCEPT__ */
int wait_mp_task_accept = 0;
int wait_mp_rom_drv_disable = 0;
int rval = 0;
dbgmckk("submit_mp_task started with task # %d\n",
mp_task
);
drv_communication =
(drv_intercom_t *) &state -> MC_BMEM[TR_CNTR_BUF_BMEM_ADDR];
switch (mp_task)
{
case data_transfer_mp_task :
case transfer_abort_mp_task :
case drq_data_transfer_mp_task :
args_num =
(sizeof(trans_desk_t) +
(sizeof(*drv_communication -> mp_args.args_area)-1)
) / sizeof(*drv_communication -> mp_args.args_area);
channel = task_args -> transfer.dev_num;
channel_state = &state -> all_channels_state[channel];
dbgmckk("submit_mp_task: mp_task = 0x%x, args_num = 0x%x\n",
mp_task, args_num);
/*
dbgmckk("submit_mp_task: sizeof(trans_desk_t) = 0x%x\n", sizeof(trans_desk_t));
dbgmckk("submit_mp_task: sizeof(*drv_communication -> mp_args.args_area) = 0x%x\n",
sizeof(*drv_communication -> mp_args.args_area));*/
break;
case drv_load_mp_task :
if (task_args != NULL)
args_num = sizeof(drv_communication -> mp_args.args_area);
else
args_num = 0;
if (mp_task_results != NULL)
mp_task_results -> mp_init_results.mp_error_code = 0;
break;
case mp_timer_intr_set_mp_task :
args_num =
(sizeof(mp_tm_set_t) +
(sizeof(*drv_communication -> mp_args.args_area)-1)
) / sizeof(*drv_communication -> mp_args.args_area);
break;
case init_streaming_mp_task :
args_num =
(sizeof(init_strm_t) +
(sizeof(*drv_communication -> mp_args.args_area)-1)
) / sizeof(*drv_communication -> mp_args.args_area);
channel = task_args -> transfer.dev_num;
channel_state = &state -> all_channels_state[channel];
if (mp_task_results != NULL)
mp_task_results -> transfer.mp_error_code = 0;
break;
case halt_streaming_mp_task :
args_num =
(sizeof(halt_strm_t) +
(sizeof(*drv_communication -> mp_args.args_area)-1)
) / sizeof(*drv_communication -> mp_args.args_area);
break;
case init_trans_state_mp_task :
args_num =
(sizeof(init_trst_t) +
(sizeof(*drv_communication -> mp_args.args_area)-1)
) / sizeof(*drv_communication -> mp_args.args_area);
if (mp_task_results != NULL)
mp_task_results -> init_state_res.mp_error_code = 0;
break;
case halt_trans_state_mp_task :
args_num =
(sizeof(halt_trst_t) +
(sizeof(*drv_communication -> mp_args.args_area)-1)
) / sizeof(*drv_communication -> mp_args.args_area);
break;
case set_timetable_mp_task :
args_num =
(sizeof(set_timetable_t) +
(sizeof(*drv_communication -> mp_args.args_area)-1)
) / sizeof(*drv_communication -> mp_args.args_area);
break;
case device_adapter_write_mp_task :
case device_adapter_read_mp_task :
args_num =
(sizeof(adapter_access_t) +
(sizeof(*drv_communication -> mp_args.args_area)-1)
) / sizeof(*drv_communication -> mp_args.args_area);
if (mp_task_results != NULL)
mp_task_results -> reg_read_results.mp_error_code = 0;
break;
case set_cnct_polling_mp_task :
args_num =
(sizeof(cnct_poll_args_t) +
(sizeof(*drv_communication -> mp_args.args_area)-1)
) / sizeof(*drv_communication -> mp_args.args_area);
break;
case halt_trans_mode_mp_task :
case reset_cnct_polling_mp_task :
args_num = 0;
break;
case no_mp_task :
default:
ME90_LOG(state, ME90_DL_ERROR,
"submit_mp_task invalid MP task # %d\n",
mp_task
);
return EINVAL;
}
dbgmckk("MCKK: submit_mp_task: before spin_mutex_enter, mutex_enter_done = %d\n", mutex_enter_done);
if (!mutex_enter_done)
{
mutex_enter(&state->mutex); /* start MUTEX */
}
dbgmckk("MCKK: submit_mp_task: after spin_mutex_enter, mutex_enter_done = %d\n", mutex_enter_done);
while (state -> drv_comm_busy && !restart)
{
cv_wait_sig(&state -> drv_comm_cv, &state->mutex);
// cv_spin_wait(&state -> drv_comm_cv, &state->lock);
}
dbgmckk("MCKK: submit_mp_task: after cv_spin_wait mp_task #%d\n", mp_task);
if (!restart)
state -> drv_comm_busy = 1;
else if (!state -> drv_comm_busy)
ME90_LOG(state, ME90_DL_ERROR,
"submit_mp_task interdriver communication area not locked\n"
);
dbgmckk("MCKK: submit_mp_task: mp_drv_started = %d, mp_task #%d\n", state -> mp_drv_started, mp_task);
if (!state -> mp_drv_started && mp_task != drv_load_mp_task)
{
dbgmckk("MCKK: submit_mp_task: !state -> mp_drv_started && mp_task != drv_load_mp_task case\n");
if (!restart)
{
state -> drv_comm_busy = 0;
cv_broadcast(&state -> drv_comm_cv);
}
if (!mutex_enter_done)
{
mutex_exit(&state->mutex); /* end MUTEX */
}
ME90_LOG(state, ME90_DL_ERROR,
"submit_mp_task MP driver did not strarted up\n"
);
return EINVAL;
}
dbgmckk("MCKK: submit_mp_task: mp_task #%d\n", mp_task);
if (state -> mp_state != started_mp_state && mp_task != drv_load_mp_task)
{
ME90_LOG(state, ME90_DL_ERROR,
"submit_mp_task MP driver is in abnormal state\n"
);
if (state -> mp_state == crash_mp_state)
{
if (!restart)
{
state -> drv_comm_busy = 0;
cv_broadcast(&state -> drv_comm_cv);
}
if (!mutex_enter_done)
{
mutex_exit(&state->mutex); /* end MUTEX */
}
ME90_LOG(state, ME90_DL_ERROR,"submit_mp_task MP driver crash\n");
return EMPCRASH;
}
else if ((!(state -> drv_general_modes & RETRIEVE_MP_HANGUP_DRV_MODE) &&
state -> mp_state == hangup_mp_state ) ||
(!(state -> drv_general_modes & RETRIEVE_DEV_FAULT_DRV_MODE) &&
state -> mp_state == fault_mp_state ) ||
(!(state -> drv_general_modes & RETRIEVE_DEV_FAULT_DRV_MODE) &&
state -> mp_state == adapter_abend_mp_state)
)
{
if (state -> mp_state == hangup_mp_state)
rval = EMPHANGUP;
else if (state -> mp_state == fault_mp_state)
rval = EDEVFAULT;
else if (state -> mp_state == adapter_abend_mp_state)
rval = EADPTABEND;
else
rval = EIO;
if (!restart)
{
state -> drv_comm_busy = 0;
cv_broadcast(&state -> drv_comm_cv);
}
if (!mutex_enter_done)
{
mutex_exit(&state->mutex); /* end MUTEX */
}
ME90_LOG(state, ME90_DL_ERROR,
"submit_mp_task abnormal device or MP state\n"
);
return rval;
}
if (!mutex_enter_done)
{
mc_rd_reg_t gen_reg_state;
gen_reg_state.RGEN_read = 0;
mutex_exit(&state->mutex); /* end MUTEX */
rval = me90_retrieve_trans_mode(state,1,0,gen_reg_state);
if (!mutex_enter_done)
{
mutex_enter(&state->mutex); /* start MUTEX */
}
if (rval != 0)
{
state -> mp_state = crash_mp_state;
me90drv_delete_connection_polling(state, EMPCRASH);
if (!restart)
{
state -> drv_comm_busy = 0;
cv_broadcast(&state -> drv_comm_cv);
}
if (!mutex_enter_done)
{
mutex_exit(&state->mutex); /* end MUTEX */
}
ME90_LOG(state, ME90_DL_ERROR,
"submit_mp_task MP driver restart failed\n"
);
return EMPCRASH;
}
}
else
{
if (!restart)
{
state -> drv_comm_busy = 0;
cv_broadcast(&state -> drv_comm_cv);
}
if (!mutex_enter_done)
{
mutex_exit(&state->mutex); /* end MUTEX */
}
ME90_LOG(state, ME90_DL_ERROR,
"submit_mp_task MP driver cannot be restarted\n"
);
if (state -> mp_state == hangup_mp_state)
rval = EMPHANGUP;
else if (state -> mp_state == fault_mp_state)
rval = EDEVFAULT;
else if (state -> mp_state == adapter_abend_mp_state)
rval = EADPTABEND;
else
rval = EIO;
return rval;
}
switch (mp_task)
{
case data_transfer_mp_task :
case transfer_abort_mp_task :
case drq_data_transfer_mp_task :
case init_streaming_mp_task :
case reset_cnct_polling_mp_task:
if (!restart)
{
state -> drv_comm_busy = 0;
cv_broadcast(&state -> drv_comm_cv);
}
if (!mutex_enter_done)
{
mutex_exit(&state->mutex); /* end MUTEX */
}
return EMPRESTART;
case halt_streaming_mp_task :
case mp_timer_intr_set_mp_task :
case init_trans_mode_mp_task :
case init_trans_state_mp_task :
case halt_trans_state_mp_task :
case set_timetable_mp_task :
case device_adapter_write_mp_task :
case device_adapter_read_mp_task :
case halt_trans_mode_mp_task :
case set_cnct_polling_mp_task :
break;
case no_mp_task :
case drv_load_mp_task :
default :
state -> mp_state = crash_mp_state;
me90drv_delete_connection_polling(state, EMPCRASH);
if (!restart)
{
state -> drv_comm_busy = 0;
cv_broadcast(&state -> drv_comm_cv);
}
if (!mutex_enter_done)
{
mutex_exit(&state->mutex); /* end MUTEX */
}
ME90_LOG(state, ME90_DL_ERROR,
"submit_mp_task invalid MP task # %d\n",
mp_task
);
return EINVAL;
}
}
#ifndef __WAIT_MP_TASK_ACCEPT__
/*
* Waiting Loop of last task field freed by MP driver
*/
if (!mutex_enter_done)
{
mutex_exit(&state->mutex); /* end MUTEX */
}
waiting_time = 0;
task_accepted = 0;
while (waiting_time < TASK_ACCEPT_BY_MP_TIME && !task_accepted)
{
for (cur_tryon = 0; cur_tryon < TASK_ACCEPT_BY_MP_TRYON; cur_tryon ++)
{
if (drv_communication -> mp_task != no_mp_task){
continue;
}
task_accepted = 1;
break;
};
if (task_accepted)
break;
udelay(TASK_ACCEPT_BY_MP_DELAY_TIME);
/* drv_usecwait(TASK_ACCEPT_BY_MP_DELAY_TIME); */
waiting_time += TASK_ACCEPT_BY_MP_DELAY_TIME;
};
#else
wait_mp_task_accept = 1;
#endif /* __WAIT_MP_TASK_ACCEPT__ */
if (drv_communication -> mp_task != no_mp_task)
{
ME90_LOG(state, ME90_DL_ERROR,
"submit_mp_task MP hangup - MP task field busy by task # %d\n",
drv_communication -> mp_task
);
if (!mutex_enter_done)
{
mutex_enter(&state->mutex); /* start MUTEX */
}
state -> mp_state = hangup_mp_state;
me90drv_delete_connection_polling(state, EMPHANGUP);
if (!restart)
{
state -> drv_comm_busy = 0;
cv_broadcast(&state -> drv_comm_cv);
}
if (!mutex_enter_done)
{
mutex_exit(&state->mutex); /* end MUTEX */
}
return EMPHANGUP;
}
for (cur_arg = 0; cur_arg < args_num; cur_arg ++)
{
drv_communication -> mp_args.args_area[cur_arg] =
task_args -> args_area[cur_arg];
ME90_LOG(state, ME90_DL_TRACE, "submit_mp_task: task_args -> args_area[%d] = 0x%x\n",
cur_arg, task_args -> args_area[cur_arg]);
}
drv_communication -> mp_task = mp_task;
if (trans_res_info != NULL)
#ifdef _MP_TIME_USE_
READ_MP_TIME(trans_res_info -> transfer_start);
#else
trans_res_info -> transfer_start = ddi_gethrtime();
#endif /* _MP_TIME_USE_ */
wait_mp_task_accept |= (mp_task == drv_load_mp_task ||
mp_task == init_streaming_mp_task ||
mp_task == init_trans_mode_mp_task ||
mp_task == init_trans_state_mp_task ||
mp_task == device_adapter_read_mp_task ||
mp_task == reset_cnct_polling_mp_task
);
wait_mp_rom_drv_disable = (mp_task == drv_load_mp_task);
rval = mckk_interrupt_mp(state,mp_task == drv_load_mp_task,
wait_mp_task_accept, wait_mp_rom_drv_disable);
if (!mutex_enter_done)
{
mutex_enter(&state->mutex); /* start MUTEX */
}
if (rval == 0 && mp_task == drv_load_mp_task)
state -> mp_state = started_mp_state;
else if (rval == EMPROMDISABLE) {
drv_communication -> mp_task = no_mp_task;
state -> mp_state = halted_mp_state;
} else if (rval != 0) {
ME90_LOG(state, ME90_DL_ERROR,
"submit_mp_task MP hangup - not take the task %d\n",
drv_communication -> mp_task
);
state -> mp_state = hangup_mp_state;
me90drv_delete_connection_polling(state, EMPHANGUP);
}
if (
mp_task == init_streaming_mp_task ||
mp_task == init_trans_state_mp_task ||
mp_task == device_adapter_read_mp_task
)
{
char task_not_complete = 0;
#ifndef __WAIT_SPARC_TASK_ACCEPT__
/*
* Waiting for sparc task field will be set MP driver
*/
waiting_time = 0;
task_accepted = 0;
while (waiting_time < TASK_ACCEPT_BY_MP_TIME && !task_accepted)
{
for (cur_tryon = 0; cur_tryon<TASK_ACCEPT_BY_MP_TRYON; cur_tryon ++)
{
if (drv_communication -> sparc_task == no_sparc_task){
continue;
}
task_accepted = 1;
break;
};
if (task_accepted)
break;
udelay(TASK_ACCEPT_BY_MP_DELAY_TIME);
/* drv_usecwait(TASK_ACCEPT_BY_MP_DELAY_TIME); */
waiting_time += TASK_ACCEPT_BY_MP_DELAY_TIME;
};
#else
#endif /* __WAIT_SPARC_TASK_ACCEPT__ */
for (cur_arg = 0;
cur_arg < (sizeof(drv_communication -> sparc_args.args_area) +
(sizeof(*drv_communication -> sparc_args.args_area) - 1)
) / sizeof(*drv_communication -> sparc_args.args_area);
cur_arg ++)
{
mp_task_results -> args_area[cur_arg] =
drv_communication -> sparc_args.args_area[cur_arg];
}
if ((
drv_communication -> sparc_task != init_streaming_end_mp_task &&
drv_communication -> sparc_task != init_trans_state_end_mp_task &&
drv_communication -> sparc_task !=
device_adapter_read_end_mp_task
) &&
rval == 0
)
{
task_not_complete = 1;
if (mp_task == drv_load_mp_task)
{
mp_task_results -> mp_init_results.mp_error_code =
NOT_COMPLETE_TASK_BY_MP_ERROR;
ME90_LOG(state, ME90_DL_ERROR,
"submit_mp_task MP driver load failed: not completed\n"
);
}
else if (mp_task == init_trans_mode_mp_task)
{
mp_task_results -> init_trans_results.mp_error_code =
NOT_COMPLETE_TASK_BY_MP_ERROR;
ME90_LOG(state, ME90_DL_ERROR,
"submit_mp_task init transfer mode failed: "
"not completed\n"
);
}
else if (mp_task == init_streaming_mp_task)
{
mp_task_results -> transfer.mp_error_code =
NOT_COMPLETE_TASK_BY_MP_ERROR;
ME90_LOG(state, ME90_DL_ERROR,
"submit_mp_task init streaming transfer failed: "
"not completed\n"
);
}
else if (mp_task == init_trans_state_mp_task)
{
mp_task_results -> init_state_res.mp_error_code =
NOT_COMPLETE_TASK_BY_MP_ERROR;
ME90_LOG(state, ME90_DL_ERROR,
"submit_mp_task init channel transfer state failed: "
"not completed\n"
);
}
else if (mp_task == device_adapter_read_mp_task)
{
mp_task_results -> reg_read_results.mp_error_code =
NOT_COMPLETE_TASK_BY_MP_ERROR;
ME90_LOG(state, ME90_DL_ERROR,
"submit_mp_task device aregister read failed: "
"not completed\n"
);
}
}
if (mp_task_results -> mp_init_results.mp_error_code != 0 &&
mp_task == drv_load_mp_task &&
rval == 0 &&
!task_not_complete
)
{
ME90_LOG(state, ME90_DL_ERROR,
"submit_mp_task MP driver load failed: error 0x%02x\n",
mp_task_results -> mp_init_results.mp_error_code & 0xff
);
}
if (mp_task_results -> transfer.mp_error_code != 0 &&
mp_task == init_streaming_mp_task &&
rval == 0 &&
!task_not_complete
)
{
ME90_LOG(state, ME90_DL_ERROR,
"submit_mp_task init streaming transfer: error 0x%02x\n",
mp_task_results -> transfer.mp_error_code & 0xff
);
}
if (mp_task == init_trans_state_mp_task)
{
if (mp_task_results -> init_state_res.mp_error_code != 0 &&
rval == 0 &&
!task_not_complete
)
{
ME90_LOG(state, ME90_DL_ERROR,
"submit_mp_task init channel transfer state: error"
" 0x%02x\n",
mp_task_results -> init_state_res.mp_error_code & 0xff
);
}
}
if (mp_task == device_adapter_read_mp_task)
{
if (mp_task_results -> reg_read_results.mp_error_code != 0 &&
rval == 0 &&
!task_not_complete
)
{
ME90_LOG(state, ME90_DL_ERROR,
"submit_mp_task read device reg: error 0x%02x\n",
mp_task_results -> reg_read_results.mp_error_code & 0xff
);
}
task_args -> dev_adapter_access.reg_value =
mp_task_results -> reg_read_results.read_value;
}
drv_communication -> sparc_task = no_sparc_task;
}
if (rval == 0 && channel_state != NULL)
{
if (mp_task == data_transfer_mp_task ||
mp_task == drq_data_transfer_mp_task ||
mp_task == init_streaming_mp_task
)
{
channel_state -> in_progress = 1;
cv_broadcast(&state -> trans_start_cv);
}
}
if (!restart)
{
state -> drv_comm_busy = 0;
cv_broadcast(&state -> drv_comm_cv);
}
if (!mutex_enter_done)
{
mutex_exit(&state->mutex); /* end MUTEX */
}
ME90_LOG(state, ME90_DL_TRACE,"submit_mp_task finished for task # %d\n",
mp_task
); /* !!!!! */
return rval;
}
/*
* Release all transfer in the list of ready asynchronous transfers
*/
/*ARGSUSED*/
static void
mckk_release_all_async_trans(
mcb_state_t *state,
int channel)
{
me90drv_chnl_state_t *channel_state = NULL;
me90drv_trans_buf_t *trans_buf_p = NULL;
ME90_LOG(state, ME90_DL_TRACE,
"mckk_release_all_async_trans started for channel %d\n",
channel);
channel_state = &state -> all_channels_state[channel];
while (1) {
mutex_enter(&state->mutex); /* start MUTEX */
trans_buf_p = channel_state -> ready_atrans_start;
if (trans_buf_p == NULL) {
mutex_exit(&state->mutex); /* end MUTEX */
break;
}
channel_state -> ready_atrans_start =
trans_buf_p -> next_trans_buf;
if (channel_state -> ready_atrans_start == NULL)
channel_state -> ready_atrans_end = NULL;
channel_state -> ready_atrans_size --;
channel_state -> async_trans_num --;
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_WARNING,
"mckk_release_all_async_trans asynchronous transfer"
" 0x%08x in the channel %d will be deleted\n",
trans_buf_p, channel);
me90drv_release_async_trans(state, channel, trans_buf_p);
}
if (channel_state -> async_trans_num != 0) {
ME90_LOG(state, ME90_DL_ERROR,
"mckk_release_all_async_trans not empty asynchronous"
" transfer counter = %d in the channel %d\n",
channel_state -> async_trans_num, channel);
channel_state -> async_trans_num = 0;
}
ME90_LOG(state, ME90_DL_TRACE,
"mckk_release_all_async_trans finished for channel %d\n",
channel);
}
#ifdef DEBUG_BUF_USE
/*
* Output message from buffer to the console and/or syslog with cmn_err
*/
/*ARGSUSED*/
static void mckk_out_debug_msg_buf(void)
{
int cur_line = 0;
if (me90_debug_buf_line == 0 && !me90_debug_buf_overflow)
return;
if (me90_debug_buf_overflow)
{
for (cur_line = me90_debug_buf_line;
cur_line < ME90_DEBUG_MSG_LINE_NUM;
cur_line ++
)
{
printk(KERN_ERR "^%s\n",
&me90_debug_msg_buf[cur_line *
ME90_DEBUG_MSG_LINE_SIZE
]
);
// Sol ticks delay(1 * drv_usectohz(10000));
/* Lin mksec */ udelay(1 * 10000);
}
}
for (cur_line = 0;
cur_line < me90_debug_buf_line;
cur_line ++
)
{
printk(KERN_ERR "^%s\n",
&me90_debug_msg_buf[cur_line *
ME90_DEBUG_MSG_LINE_SIZE
]
);
// Sol ticks delay(1 * drv_usectohz(10000));
/* Lin mksec */ udelay(1 * 10000);
}
}
#endif /* DEBUG_BUF_USE */
/*
* Driver close entry point
*/
/*ARGSUSED*/
static int
mckk_close(struct inode *inode, struct file *file)
{
mcb_state_t *state;
me90drv_chnl_state_t *channel_state = NULL;
dev_t dev = MKDEV(mckk_major, iminor(inode));
int instance = 0;
int channel = 0;
u_long cur_clock_ticks = 0;
u_long timeout_clock_ticks = 0;
struct mckk_file_private* pdata;
int rval = 0;
instance = MCB_INST(dev);
channel = MCB_CHAN(dev);
ME90_LOG(NULL, ME90_DL_TRACE,"mckk_close started, instance %d channel %d\n",
instance,channel
);
state = mckk_states[instance];
if (state == NULL) {
printk("~%s~_close: unattached instance %d\n", mod_name, instance);
return (ENXIO);
};
channel_state = &state -> all_channels_state[channel];
/*
* Acquire the mutex
*/
mutex_enter(&state->mutex);
/*
* Channel freeing waiting for
*/
drv_getparm(LBOLT,&cur_clock_ticks);
timeout_clock_ticks =
cur_clock_ticks + drv_usectohz(CHANNEL_FREE_TIMEOUT_DEF_VALUE);
while (channel_state -> busy || channel_state -> wait_list_start != NULL ||
channel_state -> in_progress_start != NULL ||
channel_state -> completed_trans_start != NULL ||
channel_state -> term_trans_processed
)
{
rval = cv_timedwait(&state -> channel_cv, &state->mutex,timeout_clock_ticks);
// rval = cv_spin_timedwait(&state -> channel_cv, &state->lock,timeout_clock_ticks);
if (rval < 0)
{
ME90_LOG(state, ME90_DL_ERROR,
"mckk_close waiting for freeing of channel %d timeouted\n",
channel
);
if (!channel_state -> streaming || channel_state -> pseudostreaming)
{
mckk_delete_all_exec_trans(state, channel, ETIME, 0, 1);
}
break;
}
}
if (channel_state -> completed_trans_start != NULL ||
channel_state -> term_trans_processed
)
{
mutex_exit(&state->mutex);
mckk_terminate_dma_trans(state,channel);
mutex_enter(&state->mutex);
}
if (channel_state -> ready_atrans_start != NULL) {
mutex_exit(&state->mutex);
mckk_release_all_async_trans(state, channel);
mutex_enter(&state->mutex);
}
if (channel_state -> drq_queue_start != NULL ||
channel_state -> drq_queue_end != NULL
)
{
remove_drq_queue(state,channel);
}
if (channel_state -> last_term_trans_buf != NULL)
{
me90drv_delete_trans_header(state,channel_state -> last_term_trans_buf);
channel_state -> last_term_trans_buf = NULL;
}
/*
* Mark the channel closed in the map
*/
channel_state -> trans_num = 0;
state->open_channel_map &= ~CHNL_NUM_TO_MASK(channel);
/*
* If last channel closed, We are no longer open
*/
if (state->open_channel_map == 0)
{
state->open_flags = 0;
state->opened = 0;
};
if (state->opened == 0)
{
/*
* Remove hanguped MP timer interrupts and their requests
*/
if (state -> mp_timer_intrs.mp_intr_mode_on == 1)
{
mp_drv_args_t mp_timer_reset_args;
mp_timer_reset_args.mp_timer_set.timer_interval = 0;
submit_mp_task(state,mp_timer_intr_set_mp_task,
&mp_timer_reset_args,
1,
NULL,
NULL,
0
);
remove_mp_timer_intr(state);
state -> mp_timer_intrs.mp_intr_mode_on = -1;
}
/*
* Interdriver communication area freeing
*/
drv_getparm(LBOLT,&cur_clock_ticks);
timeout_clock_ticks =
cur_clock_ticks + drv_usectohz(DRV_COMM_FREE_TIMEOUT_DEF_VALUE);
while (state -> drv_comm_busy)
{
rval = cv_timedwait(&state->drv_comm_cv, &state->mutex,timeout_clock_ticks);
if (rval < 0)
{
ME90_LOG(state, ME90_DL_ERROR,
"mckk_close waiting for freeing of interdriver "
"communication area timeouted\n"
);
state -> drv_comm_busy = 0;
cv_broadcast(&state -> drv_comm_cv);
break;
}
}
}
/*
* Drop the mutex
*/
pdata = file->private_data;
if (pdata == NULL) {
printk("%s: No privat data\n", __FUNCTION__);
} else {
pdata->count--;
if (pdata->count == 0) {
kfree(pdata);
file->private_data = NULL;
}
}
mutex_exit(&state->mutex);
if (!state->opened)
{
if ((state -> connection_state & MODE_ON_CONNECTION_STATE) ||
(state -> connection_state & MP_TAKE_CONNECTION_STATE) ||
(state -> connection_state & IS_SET_CONNECTION_STATE) ||
state -> connection_events != NULL ||
state -> max_cnct_events_num > 0
)
mcb_reset_connection_polling(state, 0);
}
ME90_LOG(state, ME90_DL_TRACE,"mckk_close succesed, instance %d channel %d\n",
instance,channel
);
#ifdef DEBUG_BUF_USE
if (!state->opened)
mckk_out_debug_msg_buf();
#endif /* DEBUG_BUF_USE */
return 0;
}
/*
* Character (raw) read and write routines, called via read(2) and
* write(2). These routines perform "raw" (i.e. unbuffered) i/o.
* Since they're so similar, there's actually one 'rw' routine for both,
* these devops entry points just call the general routine with the
* appropriate flag.
*/
/*ARGSUSED*/
static ssize_t
mckk_read(struct file *pfile, char *buf, size_t sz, loff_t *lf)
{
dev_t dev = file_mckk_dev(pfile);
struct uio *uio_p;
mcb_state_t *state;
int instance;
int rval;
ME90_LOG(NULL, ME90_DL_TRACE,"mckk_read started\n");
instance = MCB_INST(dev);
state = mckk_states[instance];
if (state == NULL) {
printk("~%s~_write: unattached instance %d\n", mod_name, instance);
return (ENXIO);
};
uio_p = kmalloc(sizeof(uio_t), GFP_KERNEL);
uio_p -> uio_offset = 0;
if (uio_p <= 0) {
printk ("Error allocated memory\n");
return 1;
}
/*
* Here we believe that buf is always in user adress space.. We
* allocate a kernel block for coping the buf into the one. Later may
* be used ddi mapping user memory block (here buf) to the kernel
* address space via pgd, pmd, pte (pgd, pmhd, pmld, pte in e2k terms)
*/
uio_p->uio_iov->iov_base = kmalloc(sz, GFP_KERNEL);
if (uio_p ->uio_iov->iov_base <= 0 ) {
kfree (uio_p);
printk ("Error allocated memory\n");
return 1;
}
uio_p ->uio_iov-> iov_len = sz;
uio_p -> uio_iovcnt = 1;
uio_p -> uio_segflg = UIO_SYSSPACE;
uio_p -> uio_resid = uio_p -> uio_iov -> iov_len;
uio_p -> uio_offset = 0;
rval = mcb_rdwr(dev, uio_p, B_READ,NULL);
if (ddi_copyout(uio_p ->uio_iov->iov_base, buf, sz)) {
printk ("Error copy_to_user\n");
}
kfree(uio_p ->uio_iov->iov_base);
kfree(uio_p);
return rval;
}
/*ARGSUSED*/
static ssize_t
mckk_write(struct file *pfile, const char *buf, size_t sz, loff_t *lf)
{
dev_t dev;
struct uio *uio_p;
mcb_state_t *state;
int instance;
ME90_LOG(NULL, ME90_DL_TRACE,"mckk_write started\n");
dev = file_mckk_dev(pfile);
instance = MCB_INST(dev);
state = mckk_states[instance];
if (state == NULL) {
printk("~%s~_write: unattached instance %d\n", mod_name, instance);
return (ENXIO);
};
uio_p = kmalloc(sizeof(uio_t), GFP_KERNEL);
uio_p -> uio_offset = 0;
if (uio_p <= 0) {
printk ("Error allocated memory\n");
return 1;
}
/*
* Here we believe that buf is always in user adress space.. We
* allocate a kernel block for coping the buf into the one. Later may
* be used ddi mapping user memory block (here buf) to the kernel
* address space via pgd, pmd, pte (pgd, pmhd, pmld, pte in e2k terms)
*/
uio_p->uio_iov->iov_base = kmalloc(sz, GFP_KERNEL);
if (uio_p ->uio_iov->iov_base <= 0 ) {
kfree (uio_p);
printk ("Error allocated memory\n");
return 1;
}
uio_p ->uio_iov-> iov_len = sz;
uio_p -> uio_iovcnt = 1;
uio_p -> uio_segflg = UIO_SYSSPACE;
uio_p -> uio_resid = uio_p -> uio_iov -> iov_len;
uio_p -> uio_offset = 0;
if (ddi_copyin((void *)buf, uio_p ->uio_iov->iov_base, sz)) {
kfree(uio_p ->uio_iov->iov_base);
kfree(uio_p);
printk ("Error copy_from_user\n");
return 1;
}
return (mcb_rdwr(dev, uio_p, B_WRITE,NULL));
}
/*
* Get appropriate burst sizes bitmap in accordance with transfer request
* specifications and system and SBus requirements
*/
/*ARGSUSED*/
static int
mckk_get_burst_sizes(
mcb_state_t *state,
me90drv_chnl_state_t *channel_state,
me90drv_trans_spec_t *transfer_spec,
caddr_t trans_base_addr,
size_t trans_byte_size,
int *allowed_burst_sizes)
{
int allowed_burst = 0;
int cur_burst = 0;
int trans_base_addr_align = 0;
int trans_byte_size_align = 0;
ME90_LOG(state, ME90_DL_TRACE,"mckk_get_burst_sizes started\n");
if (transfer_spec != NULL) {
allowed_burst = transfer_spec -> burst_sizes;
allowed_burst &= MCB_ENABLE_BURST_SIZES;
if (allowed_burst == 0) {
ME90_LOG(state, ME90_DL_ERROR,
"mckk_get_burst_sizes - empty allowed %02x & "
"desirable %02x burst sizes bitmap\n",
MCB_ENABLE_BURST_SIZES,
transfer_spec -> burst_sizes);
return EINVAL;
}
} else
allowed_burst = state -> system_burst & MCB_ENABLE_BURST_SIZES;
if ((allowed_burst & state -> system_burst) == 0) {
ME90_LOG(state, ME90_DL_ERROR,
"mckk_get_burst_sizes - empty allowed %02x & enable"
" %02x burst sizes bitmap\n",
allowed_burst,state -> system_burst);
return EINVAL;
}
allowed_burst &= state -> system_burst;
ME90_LOG(state, ME90_DL_TRACE,"mckk_get_burst_sizes, allowed_burst = %x\n", allowed_burst);
cur_burst = 0x1;
while (cur_burst <= allowed_burst) {
if ((long) trans_base_addr & cur_burst)
break;
cur_burst <<= 1;
}
ME90_LOG(state, ME90_DL_TRACE,"mckk_get_burst_sizes, cur_burst = %x\n", cur_burst);
trans_base_addr_align = cur_burst | (cur_burst - 1);
ME90_LOG(state, ME90_DL_TRACE,"mckk_get_burst_sizes, trans_base_addr_align = %x\n", trans_base_addr_align);
cur_burst = 0x1;
while (cur_burst <= allowed_burst) {
if ((int) trans_byte_size & cur_burst)
break;
cur_burst <<= 1;
}
ME90_LOG(state, ME90_DL_TRACE,"mckk_get_burst_sizes, cur_burst = %x\n", cur_burst);
trans_byte_size_align = cur_burst | (cur_burst - 1);
ME90_LOG(state, ME90_DL_TRACE,"mckk_get_burst_sizes, trans_byte_size_align = %x\n", trans_byte_size_align);
*allowed_burst_sizes = trans_base_addr_align & trans_byte_size_align &
allowed_burst;
#if defined(__BLOCK_BUFFER_USE__)
if (transfer_spec != NULL) {
if (transfer_spec -> io_mode_flags & ONLY_UNBUF_IO_MODE)
*allowed_burst_sizes = allowed_burst;
}
#endif /* __BLOCK_BUFFER_USE__ */
ME90_LOG(state, ME90_DL_TRACE,"mckk_get_burst_sizes successed, allowed_burst_sizes = %x\n", *allowed_burst_sizes);
return 0;
}
/*
* Take new synchronous I/O data transfer
*/
/*ARGSUSED*/
static int
mckk_take_new_trans(
mcb_state_t * state,
int channel,
trans_buf_t * trans_buf_p
/* int op_flags*/
)
{
me90drv_chnl_state_t * channel_state = &state -> all_channels_state[channel];
trans_spec_t * transfer_spec = NULL;
// u_int trans_base_addr = 0;
caddr_t trans_base_addr = 0;
size_t buf_byte_size = 0;
ME90_LOG(state, ME90_DL_TRACE,
"mckk_take_new_trans started for channel %d, trans_buf_p = 0x%lx\n",
channel, trans_buf_p
);
if (!trans_buf_p -> trans_buf_desc.drv_buf_used)
{
// transfer_spec = trans_buf_p -> trans_buf_desc.bp -> b_private;
transfer_spec = trans_buf_p -> trans_buf_desc.uio_p -> transfer_spec;
if (transfer_spec == NULL)
trans_buf_p -> multi_buf_flag = 1;
else if (transfer_spec -> buf_byte_size >
trans_buf_p -> trans_buf_desc.uio_p -> uio_iov[0].iov_len
/*trans_buf_p -> trans_buf_desc.bp -> b_bcount*/)
trans_buf_p -> multi_buf_flag = 1;
else
trans_buf_p -> multi_buf_flag = 0;
/* trans_base_addr = (u_int) trans_buf_p -> trans_buf_desc.bp -> b_un.b_addr;
buf_byte_size = trans_buf_p -> trans_buf_desc.bp -> b_bcount;*/
trans_base_addr = (caddr_t) trans_buf_p -> trans_buf_desc.uio_p -> uio_iov[0].iov_base;
buf_byte_size = trans_buf_p -> trans_buf_desc.uio_p -> uio_iov[0].iov_len;
}
else
{
transfer_spec = trans_buf_p -> drv_buf_p -> transfer_spec;
trans_base_addr = (caddr_t) trans_buf_p -> trans_buf_desc.buf_address;
buf_byte_size = trans_buf_p -> trans_buf_desc.buf_size;
dbgmckk("mckk_take_new_trans: trans_base_addr = 0x%lx, buf_byte_size = 0x%lx\n",
(u_long)trans_base_addr, (u_long)buf_byte_size);
}
mutex_enter(&state->mutex); /* start MUTEX */
trans_buf_p -> next_trans_buf = NULL;
channel_state -> trans_num ++;
trans_buf_p -> trans_num = channel_state -> trans_num;
if (transfer_spec != NULL)
if (transfer_spec -> trans_res_info != NULL)
transfer_spec -> trans_res_info -> trans_num = trans_buf_p -> trans_num;
if (!trans_buf_p -> trans_buf_desc.drv_buf_used &&
channel_state -> multi_buf_lock == trans_buf_p -> trans_buf_desc.uio_p
/* channel_state -> multi_buf_lock == trans_buf_p -> trans_buf_desc.bp*/) {
/* queue locked by this transfer - continue */
trans_buf_p -> next_trans_buf = channel_state -> wait_list_start;
channel_state -> wait_list_start = trans_buf_p;
if (channel_state -> wait_list_end == NULL)
channel_state -> wait_list_end = trans_buf_p;
}
else if (channel_state -> wait_list_start == NULL) {
channel_state -> wait_list_start = trans_buf_p;
channel_state -> wait_list_end = trans_buf_p;
channel_state -> wait_list_size ++;
} else {
channel_state -> wait_list_end -> next_trans_buf = trans_buf_p;
channel_state -> wait_list_end = trans_buf_p;
channel_state -> wait_list_size ++;
}
if (transfer_spec != NULL)
if (transfer_spec -> async_trans)
channel_state -> async_trans_num ++;
mutex_exit(&state->mutex); /* end MUTEX */
if (!channel_state -> streaming)
mcb_start_new_trans(state,channel);
ME90_LOG(state, ME90_DL_TRACE,
"mckk_take_new_trans successed for channel %d\n", channel);
return (0);
}
/*ARGSUSED*/
static int mckk_dostrategy(
// struct buf * bp,
uio_t * uio_p,
mcb_state_t * state
/* trans_spec_t * transfer_spec,
int op_flags*/
)
{
dev_t dev = uio_p->dev;
me90drv_chnl_state_t *channel_state = NULL;
int dev_num = MCB_DEVN(dev);
int instance = MCB_inst(dev_num);
int channel = MCB_chan(dev_num);
// trans_spec_t * transfer_spec = bp -> b_private;
trans_spec_t * transfer_spec = uio_p -> transfer_spec;
trans_buf_t * trans_buf_p = NULL;
int flags = 0;
int rval = 0;
ME90_LOG(NULL, ME90_DL_TRACE,
"mckk_dostrategy inst %d channel %d started for"
" addr 0x%08x len 0x%x\n",
instance,channel,
uio_p->uio_iov[0].iov_base, uio_p->uio_iov[0].iov_len
// bp -> b_un.b_addr,bp -> b_bcount
);
channel_state = &state -> all_channels_state[channel];
/* if (bp->b_flags & B_READ)*/
if (uio_p->op_flags & B_READ)
flags |= DDI_DMA_READ;
/* if (bp->b_flags & B_WRITE)*/
if (uio_p->op_flags & B_WRITE)
flags |= DDI_DMA_WRITE;
flags |= DDI_DMA_STREAMING;
transfer_spec -> trans_res_info -> event_start_time = ddi_gethrtime();
// (trans_spec_t *)uio_p -> transfer_spec = transfer_spec;
rval = mckk_create_trans_header(state,
// bp->b_bcount,
uio_p->uio_iov[0].iov_len,
0, /* buffer, not pseudo */
flags,
NULL, /* real buffer, not link */
// bp,
uio_p,
NULL, /* no the associated transfer */
&trans_buf_p
);
if (rval != 0)
{
ME90_LOG(state, ME90_DL_TRACE,
"mckk_dostrategy cannot create buffer for channel"
" %d\n",
channel
);
/* bp->b_resid = bp->b_bcount;
bioerror(bp, rval);
biodone(bp);*/
return rval;
}
transfer_spec -> trans_res_info -> event_end_time = ddi_gethrtime();
rval = mckk_take_new_trans(state, channel, trans_buf_p/*, op_flags*/);
if (rval != 0) {
ME90_LOG(state, ME90_DL_WARNING,
"mckk_dostrategy: mckk_take_new_trans failed for"
" channel %d\n", channel);
mcb_delete_trans_header(state, trans_buf_p);
return rval;
} else if (transfer_spec -> async_trans) {
/* bp -> b_resid = bp -> b_bcount;
biodone(bp);*/
}
ME90_LOG(state, ME90_DL_TRACE,
"mckk_dostrategy channel %d successed for"
" addr 0x%08x len 0x%x\n",
channel,
uio_p->uio_iov[0].iov_base, uio_p->uio_iov[0].iov_len
// bp -> b_un.b_addr,bp -> b_bcount
);
return 0;
}
/*ARGSUSED*/
static int mckk_strategy(
mcb_state_t * state,
int channel,
uio_t * uio_p
)
{
dev_t dev = uio_p->dev;
int dev_num = MCB_DEVN( dev);
int instance = MCB_inst(dev_num);
trans_spec_t *transfer_spec = NULL;
int multi_buf_flag = 0;
ME90_LOG(NULL, ME90_DL_TRACE,
"mckk_strategy inst %d started for channel %d\n",
instance,channel);
transfer_spec = uio_p->transfer_spec;
#ifndef __MULTIBUF_TRANS_ENABLE_
if (transfer_spec == NULL)
multi_buf_flag = 1;
else if (transfer_spec -> buf_byte_size > /*bp -> b_bcount*/uio_p->uio_iov[0].iov_len)
multi_buf_flag = 1;
else
multi_buf_flag = 0;
if (multi_buf_flag) {
ME90_LOG(state, ME90_DL_TRACE,"mckk_strategy - multi-buffer used\n");
return 0;
}
#endif /* __MULTIBUF_TRANS_ENABLE_ */
if (transfer_spec != NULL) {
if (transfer_spec->dev_access_mode == ON_DEMAND_DEV_ACCESS_MODE) {
ME90_LOG(state, ME90_DL_TRACE,
"mckk_strategy channel %d will be waiting for DRQ"
" addr 0x%08x len 0x%x\n",
channel,
uio_p->uio_iov[0].iov_base, uio_p->uio_iov[0].iov_len);
return put_drq_queue(/*bp*/ uio_p, state);
}
}
ME90_LOG(state, ME90_DL_TRACE,
"mckk_strategy channel %d finished for"
" addr 0x%08x len 0x%x\n",
channel,
uio_p->uio_iov[0].iov_base, uio_p->uio_iov[0].iov_len);
return mckk_dostrategy(uio_p,state/*,transfer_spec,op_flags*/);
}
static int uiomove(caddr_t address, long nbytes,
int rwflag, uio_t *uio_p)
{ iovec_t *iovec_p = uio_p->uio_iov;
switch (rwflag) {
case UIO_READ :
if (UIO_USERSPACE == uio_p->uio_segflg ) {
dbgmckk("uiomove: UIO_READ, writing 0x%lx bytes to user 0x%lx adress from 0x%lx\n",
nbytes, (u_long)iovec_p->iov_base, (ulong)address);
if(copy_to_user(iovec_p->iov_base, address, nbytes) != 0)
return EFAULT;
} else {
if (memcpy(iovec_p->iov_base, address, nbytes) == 0)
return EFAULT;
}
iovec_p->iov_len = nbytes;
break;
case UIO_WRITE :
if (UIO_USERSPACE == uio_p->uio_segflg ) {
dbgmckk("uiomove: UIO_WRITE, writing 0x%lx bytes to kernel 0x%lx adress from 0x%lx\n",
nbytes, (u_long)address, (u_long)iovec_p->iov_base);
if (copy_from_user(address, iovec_p->iov_base, nbytes) != 0)
return EFAULT;
} else {
if (memcpy(address, iovec_p->iov_base, nbytes) == 0)
return EFAULT;
}
break;
default :
printk ("Error operation\n");
return EFAULT;
}
return 0;
}
/*
* Perform I/O data transfer with private driver buffer use
*/
/*ARGSUSED*/
static int
mckk_drv_buf_strategy(
mcb_state_t * state,
int channel,
uio_t * uio_p,
int op_flags,
trans_spec_t * transfer_spec
)
{
mcb_drv_buf_t *trans_drv_buf_p = NULL;
trans_buf_t *trans_buf_p = NULL;
int flags = 0;
int rval = 0;
ME90_LOG(state, ME90_DL_TRACE,
"%s(): started for channel %d\n", __func__, channel);
rval = mckk_create_drv_buf(state, uio_p, op_flags, transfer_spec, &trans_drv_buf_p);
if ( rval != 0 ) {
ME90_LOG(state, ME90_DL_TRACE,
"mckk_drv_buf_strategy cannot create driver buffer header "
"for channel %d\n",
channel
);
return rval;
}
if ( op_flags & B_READ )
flags |= DDI_DMA_READ;
if ( op_flags & B_WRITE )
flags |= DDI_DMA_WRITE;
flags |= DDI_DMA_STREAMING;
transfer_spec -> trans_res_info -> event_start_time = ddi_gethrtime();
rval = mckk_create_trans_header(state,
uio_p -> uio_resid,
0, /* buffer, not pseudo */
flags,
NULL, /* real buffer, not link */
NULL,
trans_drv_buf_p, /* the associated transfer */
&trans_buf_p
);
if ( rval != 0 ) {
ME90_LOG(state, ME90_DL_TRACE,
"%s(): cannot create driver private buffer "
"for channel %d\n", __func__,
channel
);
mckk_delete_drv_buf(state,trans_drv_buf_p);
return rval;
} else {
ME90_LOG(state, ME90_DL_TRACE,
"%s(): start trans with driver private buffer "
"for channel %d from 0x%08x to 0x%08x\n", __func__,
channel, trans_buf_p -> trans_buf_desc.buf_address,
trans_drv_buf_p -> uio_p
);
}
transfer_spec -> trans_res_info -> event_end_time = ddi_gethrtime();
if ( trans_drv_buf_p -> op_flags & B_WRITE ) {
rval = uiomove(trans_buf_p -> trans_buf_desc.buf_address,
trans_drv_buf_p -> uio_p -> uio_resid,
UIO_WRITE,
trans_drv_buf_p -> uio_p
);
if ( rval != 0 ) {
trans_buf_p -> sparc_error_code = rval;
mckk_finish_trans(state, channel, trans_buf_p, 0, 1); /* canceled */
mckk_delete_drv_buf(state,trans_drv_buf_p);
return rval;
}
rval = mckk_dma_sync(state,
trans_buf_p -> trans_buf_desc.dma.prim_dev_mem,
trans_buf_p -> trans_buf_desc.buf_size,
DMA_TO_DEVICE);
if ( rval != DDI_SUCCESS ) {
ME90_LOG(state, ME90_DL_ERROR,
"mckk_drv_buf_strategy - dma_sync failed for channel"
" %d\n",
channel
);
trans_buf_p -> sparc_error_code = EFAULT;
mckk_finish_trans(state, channel, trans_buf_p, 0, 1); /* canceled */
mckk_delete_drv_buf(state,trans_drv_buf_p);
return -EFAULT;
}
}
rval = mckk_take_new_trans(state, channel, trans_buf_p);
if ( rval != 0 ) {
ME90_LOG(state, ME90_DL_TRACE,
"mckk_drv_buf_strategy: mckk_take_new_trans failed "
"for channel %d\n", channel);
mcb_delete_trans_header(state, trans_buf_p);
mckk_delete_drv_buf(state, trans_drv_buf_p);
return rval;
}
if ( transfer_spec -> async_trans ) {
ME90_LOG(state, ME90_DL_TRACE,
"mckk_drv_buf_strategy successed for channel %d async."
" transfer\n", channel);
return 0;
}
mutex_enter(&state->mutex); /* start MUTEX */
while ( !trans_drv_buf_p -> trans_completed ) {
/* ME90_LOG(state, ME90_DL_TRACE,
"mckk_drv_buf_strategy: waiting for transfer completed "
"for channel %d\n", channel);*/
cv_wait_sig(&trans_drv_buf_p -> trans_finish_cv, &state->mutex);
// cv_spin_wait(&trans_drv_buf_p -> trans_finish_cv, &state->lock);
}
mutex_exit(&state->mutex); /* end MUTEX */
rval = me90drv_finish_drv_buf_trans(state, channel, trans_buf_p);
ME90_LOG(state, ME90_DL_TRACE,
"%s(): succeeded for channel %d\n", __func__, channel);
return rval;
}
/*
* General character (raw) read/write routine
* Just verify the unit number and transfer offset & length, and call
* strategy via physio. Physio(9f) will take care of address mapping
* and locking, and will split the transfer if ncessary, based on minphys,
* possibly calling the strategy routine multiple times.
*/
/*ARGSUSED*/
static int
mcb_rdwr(
dev_t dev,
struct uio *uio_p,
int flag,
trans_spec_t *user_transfer_spec)
{
mcb_state_t * state = NULL;
me90drv_chnl_state_t * channel_state = NULL;
// struct buf * buf_p = NULL;
int instance;
int channel;
trans_spec_t transfer_spec;
trans_info_t trans_res_info;
trans_spec_t * transfer_spec_p = user_transfer_spec;
int io_mode_flags = DMA_TRANSFER_IO_MODE;
int rval = 0;
int cur_iov = 0;
size_t transfer_len = 0;
int drv_buf_using = 0;
#ifdef NO_DRV_BUF_USING
int allowed_burst = 0;
#endif
caddr_t trans_base_addr = 0;
instance = MCB_INST(dev);
channel = MCB_CHAN(dev);
state = mckk_states[instance];
if (state == NULL)
{
ME90_LOG(NULL, ME90_DL_ERROR,"mckk_rdwr - bad instance %d\n",
instance
);
return (ENXIO);
};
ME90_LOG(NULL, ME90_DL_TRACE,
"mckk_rdwr inst %d channel %d started %s\n",
instance,channel,
(flag == B_READ) ? "to read" : "to write"
);
channel_state = &state -> all_channels_state[channel];
if (transfer_spec_p != NULL)
{
io_mode_flags = transfer_spec_p -> io_mode_flags;
mckk_init_trans_results(transfer_spec_p);
}
for (cur_iov = 0; cur_iov < uio_p -> uio_iovcnt; cur_iov ++)
{
transfer_len += (uio_p -> uio_iov[cur_iov].iov_len);
}
uio_p -> uio_offset = 0;
trans_base_addr = uio_p -> uio_iov[0].iov_base;
#ifdef NO_DRV_BUF_USING /* О©╫О©╫ О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫ physio.. О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫ О©╫О©╫О©╫О©╫О©╫О©╫О©╫ */
rval = mckk_get_burst_sizes(state,
channel_state,
transfer_spec_p,
trans_base_addr,
transfer_len,
&allowed_burst
);
if (rval != 0)
{
ME90_LOG(state, ME90_DL_TRACE,
"mckk_rdwr instance %d channel %d mckk_get_burst_sizes failed\n",
instance,channel
);
return rval;
}
if (allowed_burst == 0 ||
(state -> drv_general_modes & ONLY_BUF_IO_DRV_MODE)
)
{
drv_buf_using = 1;
}
if (channel_state -> streaming && !channel_state -> pseudostreaming &&
!(io_mode_flags & BMEM_TRANSFER_IO_MODE)
)
drv_buf_using = 1;
#else
drv_buf_using = 1;
#endif
if (transfer_spec_p == NULL)
{
transfer_spec_p = &transfer_spec;
transfer_spec.buf_base = (caddr_t) trans_base_addr;
transfer_spec.buf_byte_size = transfer_len;
transfer_spec.read_write_flag = flag;
transfer_spec.async_trans = 0;
transfer_spec.io_mode_flags = DMA_TRANSFER_IO_MODE;
transfer_spec.dev_access_mode = DIRECT_DEV_ACCESS_MODE;
transfer_spec.burst_sizes = MCB_ENABLE_BURST_SIZES;
transfer_spec.timer_interval = 0;
transfer_spec.repeation_num = 0;
transfer_spec.data_waiting_time =
STREAMING_DATA_WAITING_TIME_DEF + 100000;
transfer_spec.trans_res_info = &trans_res_info;
transfer_spec.user_results_p = NULL;
mckk_init_trans_results(transfer_spec_p);
}
if ((transfer_spec_p -> io_mode_flags & ONLY_UNBUF_IO_MODE) &&
drv_buf_using
)
{
if (state -> drv_general_modes & ONLY_BUF_IO_DRV_MODE)
{
ME90_LOG(state, ME90_DL_ERROR,
"mckk_rdwr cannot use unbuffered I/O when ONLY BUF mode"
"of driver is set\n"
);
}
else
{
ME90_LOG(state, ME90_DL_ERROR,"mckk_rdwr buf used in the unbuf mode\n");
}
return EINVAL;
}
if (keep_last_trans_buf_mode)
{
trans_buf_t * prev_last_trans_buf = NULL;
mutex_enter(&state->mutex); /* start MUTEX */
prev_last_trans_buf = channel_state -> last_term_trans_buf;
channel_state -> last_term_trans_buf = NULL;
mutex_exit(&state->mutex); /* end MUTEX */
if (prev_last_trans_buf != NULL)
me90drv_delete_trans_header(state,prev_last_trans_buf);
}
ME90_LOG(state, ME90_DL_TRACE,"mckk_rdwr: drv_buf_using = %d\n", drv_buf_using);
while (1)
{
if (!drv_buf_using)
{
/* buf_p = getrbuf(KM_NOSLEEP);
if (buf_p == NULL)
{
ME90_LOG(state, ME90_DL_ERROR,"mckk_rdwr cannot allocate buf\n");
return (EINVAL);
};
buf_p -> b_private = transfer_spec_p;
rval =(physio(mckk_strategy, buf_p, dev, flag, minphys, uio_p)); */
uio_p->op_flags = flag;
uio_p->transfer_spec = transfer_spec_p;
uio_p->dev = dev;
rval = mckk_strategy(state, channel, uio_p /*flag, transfer_spec_p*/);
if (!transfer_spec_p -> async_trans || rval != 0) {
mckk_buf_trans_done(state, channel, /*buf_p*/uio_p);
/*if (buf_p != NULL)
freerbuf(buf_p);*/
}
if (rval == EMULTIBUF)
{
drv_buf_using = 1;
continue;
}
if (transfer_spec_p -> async_trans) {
kmem_free(uio_p -> uio_iov, sizeof(iovec_t));
kmem_free(uio_p, sizeof(uio_t));
}
}
else /* transfer with using driver private buffers and data copy */
{
rval = mckk_drv_buf_strategy(state,channel,uio_p,flag,transfer_spec_p);
}
break;
}
ME90_LOG(state, ME90_DL_TRACE,
"mckk_rdwr instance %d channel %d finished with res %d\n",
instance,channel,rval
);
return rval;
}
/*
* Finish I/O data transfer with private driver buffer use
*/
/*ARGSUSED*/
static int
mcb_finish_drv_buf_trans(
mcb_state_t *state,
int channel,
trans_buf_t *trans_buf_p)
{
me90drv_chnl_state_t *channel_state = NULL;
mcb_drv_buf_t *trans_drv_buf_p = NULL;
uio_t *uio_p;
trans_spec_t *transfer_spec = NULL;
int rval = 0;
ME90_LOG(state, ME90_DL_TRACE,
"mckk_finish_drv_buf_trans started for channel %d\n", channel);
channel_state = &state -> all_channels_state[channel];
if (!trans_buf_p -> trans_buf_desc.drv_buf_used ||
trans_buf_p -> drv_buf_p == NULL) {
ME90_LOG(state, ME90_DL_TRACE,
"mckk_finish_drv_buf_trans the transfer has not private"
" buffer\n");
return EINVAL;
}
trans_drv_buf_p = trans_buf_p -> drv_buf_p;
uio_p = trans_drv_buf_p -> uio_p;
transfer_spec = (trans_spec_t *) trans_drv_buf_p -> transfer_spec;
if (trans_drv_buf_p -> op_flags & B_READ) {
size_t real_trans_size = trans_buf_p -> real_trans_size;
size_t source_size = trans_buf_p -> trans_buf_desc.buf_size;
if (transfer_spec != NULL) {
if (transfer_spec -> io_mode_flags &
BMEM_TRANSFER_IO_MODE) {
if (transfer_spec -> repeation_num > 1)
source_size *=
transfer_spec -> repeation_num;
}
}
if (real_trans_size > source_size) {
ME90_LOG(state, ME90_DL_ERROR,
"mckk_finish_drv_buf_trans real transfered bytes"
" %d > buf size %d for channel %d\n",
real_trans_size, source_size,
channel);
real_trans_size =
trans_buf_p -> trans_buf_desc.buf_size;
}
if (trans_buf_p -> real_trans_size > 0) {
rval = uiomove(trans_buf_p ->
trans_buf_desc.buf_address,
min(trans_buf_p -> trans_size,
real_trans_size),
UIO_READ, trans_drv_buf_p -> uio_p);
if (rval != 0) {
trans_drv_buf_p -> trans_error = rval;
if (transfer_spec -> trans_res_info != NULL)
transfer_spec -> trans_res_info ->
trans_errno = rval;
}
ME90_LOG(state, ME90_DL_TRACE,
"mckk_finish_drv_buf_trans move %d byte(s) of"
" ready data for channel %d with res %d"
"from 0x%08x to 0x%08x\n",
min(trans_buf_p -> trans_size,
real_trans_size),
channel, rval,
trans_buf_p -> trans_buf_desc.buf_address,
trans_drv_buf_p -> uio_p);
}
}
rval = trans_drv_buf_p -> trans_error;
if (!transfer_spec -> async_trans) {
mckk_delete_drv_buf(state,trans_drv_buf_p);
trans_buf_p -> drv_buf_p = NULL;
me90drv_delete_trans_header(state,trans_buf_p);
}
ME90_LOG(state, ME90_DL_TRACE,
"mckk_finish_drv_buf_trans finished with result %d for channel"
" %d\n", rval, channel);
return rval;
}
/*
* Freeing the channel when I/O operation completed or errors occured
*/
/*ARGSUSED*/
static int
mckk_free_channel(
mcb_state_t *state,
int channel,
trans_state_t transfer_state)
{
ME90_LOG(state, ME90_DL_TRACE,
"mckk_free_channel for channel %d started\n", channel);
/*
* lock mckk state structure
*/
mutex_enter(&state->mutex); /* start MUTEX */
mckk_set_transfer_done(state, channel,transfer_state);
/*
* Drop mckk state structure
*/
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_TRACE,
"mckk_free_channel for channel %d successed\n", channel);
return (0);
}
/*
* Launch new transfer: the first from queue of waiting for execution
*/
/*ARGSUSED*/
static void
mcb_start_new_trans(
mcb_state_t *state,
int channel
/* int op_flags*/)
{
me90drv_chnl_state_t *channel_state = NULL;
int rval = 0;
trans_buf_t *new_trans_buf = NULL;
trans_buf_t *cur_trans_buf = NULL;
/* buf_t *bp = NULL;*/
ME90_LOG(state, ME90_DL_TRACE,
"mckk_start_new_trans started for channel %d\n",
channel
);
channel_state = &state -> all_channels_state[channel];
mutex_enter(&state->mutex); /* start MUTEX */
if (get_channel_state(state,channel,started_trans_state) != 0)
{
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_TRACE,
"mckk_start_new_trans - channel %d busy so far or yet\n",
channel
);
return;
}
if (state -> mp_state != started_mp_state)
{
mc_rd_reg_t gen_reg_state;
gen_reg_state.RGEN_read = 0;
ME90_LOG(state, ME90_DL_ERROR,
"mckk_start_new_trans MP driver is in abnormal"
" state\n"
);
mutex_exit(&state->mutex); /* end MUTEX */
me90_retrieve_trans_mode(state,0,0,gen_reg_state);
mutex_enter(&state->mutex); /* start MUTEX */
}
new_trans_buf = channel_state -> wait_list_start;
channel_state -> wait_list_start = new_trans_buf -> next_trans_buf;
if (channel_state -> wait_list_start == NULL)
channel_state -> wait_list_end = NULL;
channel_state -> wait_list_size --;
new_trans_buf -> next_trans_buf = NULL;
if (channel_state -> in_progress_start == NULL) {
channel_state -> in_progress_start = new_trans_buf;
} else {
channel_state -> in_progress_end -> next_trans_buf = new_trans_buf;
}
channel_state -> in_progress_end = new_trans_buf;
channel_state -> in_progress_size ++;
if (new_trans_buf -> multi_buf_flag &&
!new_trans_buf -> trans_buf_desc.drv_buf_used)
/* channel_state -> multi_buf_lock = new_trans_buf -> trans_buf_desc.bp;*/
channel_state -> multi_buf_lock = new_trans_buf -> trans_buf_desc.uio_p;
mutex_exit(&state->mutex); /* end MUTEX */
mckk_set_trans_timeout(state,channel,0);
rval = start_mckk_dma_engine(state,channel/*,op_flags*/);
if (rval != 0 && rval != EMPRESTART) {
mutex_enter(&state->mutex); /* start MUTEX */
cur_trans_buf = channel_state -> in_progress_start;
while (cur_trans_buf != NULL) {
if (cur_trans_buf == new_trans_buf) {
channel_state -> in_progress_start = NULL;
channel_state -> in_progress_end = NULL;
channel_state -> in_progress_size --;
break;
} else if (cur_trans_buf -> next_trans_buf == new_trans_buf) {
cur_trans_buf -> next_trans_buf = new_trans_buf -> next_trans_buf;
if (cur_trans_buf -> next_trans_buf == NULL)
channel_state -> in_progress_end = cur_trans_buf;
channel_state -> in_progress_size --;
break;
}
cur_trans_buf = cur_trans_buf -> next_trans_buf;
}
if (channel_state -> in_progress_start == NULL)
mckk_delete_timeout(state, channel);
mutex_exit(&state->mutex); /* end MUTEX */
if (mckk_free_channel(state, channel, aborted_trans_state) != 0) {
ME90_LOG(state, ME90_DL_TRACE,
"mckk_start_new_trans - cannot free channel %d"
" access\n", channel);
}
new_trans_buf -> sparc_error_code = rval;
mckk_finish_trans(state, channel, new_trans_buf, 0, 0);
ME90_LOG(state, ME90_DL_TRACE,
"mckk_start_new_trans: start_mckk_dma_engine failed for"
" channel %d\n", channel);
me90drv_start_new_trans(state,channel);
return;
}
if (state -> drv_general_modes & MULTI_REQ_CHANNEL_DRV_MODE) {
if (mckk_free_channel(state, channel, started_trans_state) != 0) {
ME90_LOG(state, ME90_DL_TRACE,
"mckk_start_new_trans - cannot free channel %d"
" access\n", channel);
}
mcb_start_new_trans(state, channel);
}
ME90_LOG(state, ME90_DL_TRACE,
"mckk_start_new_trans successed for channel %d\n", channel);
return;
}
/*
* Launch new transfer: the first from queue of waiting for execution
*/
/*ARGSUSED*/
static void mckk_buf_trans_done(
mcb_state_t * state,
int channel,
/* buf_t * bp*/
uio_t * uio_p
)
{
me90drv_chnl_state_t * channel_state = &state -> all_channels_state[channel];
ME90_LOG(state, ME90_DL_TRACE,"mckk_buf_trans_done started for channel %d\n",
channel
);
mutex_enter(&state->mutex); /* start MUTEX */
if (channel_state -> multi_buf_lock == 0)
{
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_TRACE,
"mckk_buf_trans_done no any lock for channel %d\n",
channel
);
return;
}
else if (/*channel_state -> multi_buf_lock != bp*/ channel_state -> multi_buf_lock != uio_p)
{
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_TRACE,
"mckk_buf_trans_done lock of other transfer for channel %d\n",
channel
);
return;
}
channel_state -> multi_buf_lock = NULL;
mutex_exit(&state->mutex); /* end MUTEX */
me90drv_start_new_trans(state,channel);
ME90_LOG(state, ME90_DL_TRACE,"mckk_buf_trans_done successed for channel %d\n",
channel
);
}
/*
* Put transfer request into queue of pending request. The transfer will be
* started only after device request receiving
*/
/*ARGSUSED*/
static int put_drq_queue(
// struct buf * bp,
uio_t * uio_p,
mcb_state_t * state
)
{
me90drv_chnl_state_t * channel_state = NULL;
dev_t dev = uio_p->dev;
int dev_num = MCB_DEVN(/*bp->b_edev*/ dev);
int channel = MCB_chan(dev_num);
drq_trans_spec_t * new_transfer = NULL;
ME90_LOG(state, ME90_DL_TRACE,
"put_drq_queue channel %d started for"
" addr 0x%08x len 0x%x\n",
channel,
uio_p->uio_iov[0].iov_base, uio_p->uio_iov[0].iov_len
// bp -> b_un.b_addr,bp -> b_bcount
);
channel_state = &state -> all_channels_state[channel];
new_transfer = kmem_alloc(sizeof(drq_trans_spec_t),KM_NOSLEEP);
if (new_transfer == NULL)
{
ME90_LOG(NULL, ME90_DL_ERROR,
"put_drq_queue channel %d cannot allocate memory for"
" transfer request structure\n",
channel
);
/* bp->b_resid = bp->b_bcount;
bioerror(bp, EINVAL);
biodone(bp);*/
return 0;
}
// new_transfer -> bp = bp;
new_transfer -> uio_p = uio_p;
new_transfer -> next_trans_spec = NULL;
/*
* lock state state structure
*/
mutex_enter(&state->mutex); /* start MUTEX */
if (channel_state -> drq_queue_start == NULL)
{
channel_state -> drq_queue_start = new_transfer;
channel_state -> drq_queue_end = new_transfer;
}
else
{
channel_state -> drq_queue_end -> next_trans_spec = new_transfer;
channel_state -> drq_queue_end = new_transfer;
}
channel_state -> drq_queue_size ++;
/*
* Drop state state structure
*/
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_TRACE,"put_drq_queue for channel %d successed\n",
channel
);
return 0;
}
/*
* Start current transfer from queue of pending request. They are
* waiting for device request receiving
*/
/*ARGSUSED*/
static int start_pending_transfer(
mcb_state_t * state,
int channel,
#ifdef _MP_TIME_USE_
u_int intr_drq_received
#else
hrtime_t intr_drq_received
#endif /* _MP_TIME_USE_ */
)
{
me90drv_chnl_state_t * channel_state = NULL;
drq_trans_spec_t * cur_transfer = NULL;
trans_spec_t * transfer_spec = NULL;
ME90_LOG(state, ME90_DL_TRACE,
"start_pending_transfer channel %d started\n",
channel
);
channel_state = &state -> all_channels_state[channel];
/*
* lock state state structure
*/
mutex_enter(&state->mutex); /* start MUTEX */
if (channel_state -> drq_queue_start == NULL)
{
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_ERROR,
"start_pending_transfer no any transfer request waiting "
"for DRQ in the channel %d\n",
channel
);
return 0;
}
cur_transfer = channel_state -> drq_queue_start;
channel_state -> drq_queue_start = cur_transfer -> next_trans_spec;
if (channel_state -> drq_queue_start == NULL)
channel_state -> drq_queue_end = NULL;
channel_state -> drq_queue_size --;
/*
* Drop state state structure
*/
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_TRACE,
"start_pending_transfer for channel %d successed\n",
channel
);
/* transfer_spec = cur_transfer -> bp -> b_private;*/
transfer_spec = cur_transfer -> uio_p -> transfer_spec;
if (transfer_spec != NULL)
if (transfer_spec -> trans_res_info != NULL)
transfer_spec -> trans_res_info -> intr_drq_received =
intr_drq_received;
/* return mckk_dostrategy(cur_transfer -> bp,state);*/
return mckk_dostrategy(cur_transfer -> uio_p,state/*,transfer_spec,cur_transfer -> uio_p -> op_flags*/);
}
static int mckk_calculate_work_hr_time(
hrtime_t start_time, /* event start time */
hrtime_t end_time /* event finish time */
)
{
return ((end_time - start_time) / 1000);
}
#ifdef _MP_TIME_USE_
/*
* Calculate same event time in microseconds.
*/
/*ARGSUSED*/
static int mckk_calculate_work_time(
u_int start_time, /* event start time */
u_int end_time /* event finish time */
)
{
int work_time;
u_int max_timer_value = 0xffffffff;
u_int max_time = start_time;
u_int min_time = end_time;
u_int internal_time = 0;
u_int external_time = 0;
int neg_time = 0;
if (end_time > start_time)
{
max_time = end_time;
min_time = start_time;
}
internal_time = max_time - min_time;
external_time = (max_timer_value - max_time + 1) + min_time;
if (internal_time <= external_time)
{
work_time = internal_time;
neg_time = (start_time < end_time);
}
else
{
work_time = external_time;
neg_time = (start_time > end_time);
}
if (neg_time)
work_time = 0 - work_time;
return (work_time * me90_mp_nsec_cycle / 1000);
}
#endif // _MP_TIME_USE_
/*
* Handle interrupt received from MP after MP timer expiration.
*/
/*ARGSUSED*/
static int handle_mp_timer_intr(
mcb_state_t * state,
#ifdef _MP_TIME_USE_
u_int intr_mp_time
#else
hrtime_t intr_mp_time
#endif /* _MP_TIME_USE_ */
)
{
mp_intr_spec_t * mp_timer_intr_spec = NULL;
int rval = 0;
u_int timer_interval = 0;
mp_intr_t * mp_timer_intr;
#ifdef _MP_TIME_USE_
u_int cur_mp_time = 0;
#else
hrtime_t cur_mp_time = 0;
#endif /* _MP_TIME_USE_ */
drv_intercom_t * drv_communication = NULL;
ME90_LOG(state, ME90_DL_TRACE,"handle_mp_timer_intr started\n");
mp_timer_intr_spec = &state -> mp_timer_intrs;
mutex_enter(&state->mutex); /* start MUTEX */
if (mp_timer_intr_spec -> mp_intr_mode_on != 1)
{
if (mp_timer_intr_spec -> mp_intr_mode_on == -1)
{
mutex_exit(&state->mutex); /* end MUTEX */
return 0; /* handuped interrupt after the mode was turn off */
}
else
{
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_ERROR,
"handle_mp_timer_intr not waiting MP timer interrupt\n"
);
return 1;
}
}
mp_timer_intr_spec -> total_intr_num ++;
if (mp_timer_intr_spec -> total_intr_num > 1)
timer_interval =
#ifdef _MP_TIME_USE_
mckk_calculate_work_time(mp_timer_intr_spec -> last_intr_time,
intr_mp_time);
#else
mckk_calculate_work_hr_time(mp_timer_intr_spec -> last_intr_time,
intr_mp_time);
#endif /* _MP_TIME_USE_ */
#ifdef _MP_TIME_USE_
if (mp_timer_intr_spec -> last_intr_time < intr_mp_time)
{
ME90_LOG(state, ME90_DL_ERROR,
"handle_mp_timer_intr prev MP timer intr time 0x%08x <"
" cur intr time 0x%08x\n",
mp_timer_intr_spec -> last_intr_time,
intr_mp_time
);
}
#else
if (mp_timer_intr_spec -> last_intr_time > intr_mp_time)
{
ME90_LOG(state, ME90_DL_ERROR,
"handle_mp_timer_intr prev MP timer intr time 0x%016xL >"
" cur intr time 0x%016xL\n",
mp_timer_intr_spec -> last_intr_time,
intr_mp_time
);
}
#endif /* _MP_TIME_USE_ */
mp_timer_intr_spec -> last_intr_time = intr_mp_time;
drv_communication =
(drv_intercom_t *) &state -> MC_BMEM[TR_CNTR_BUF_BMEM_ADDR];
#ifdef _MP_TIME_USE_
READ_MP_TIME(cur_mp_time);
#else
cur_mp_time = ddi_gethrtime();
#endif /* _MP_TIME_USE_ */
if (mp_timer_intr_spec -> cur_request_num > 0)
{
if (mp_timer_intr_spec -> cur_queue_size > 0)
{
ME90_LOG(state, ME90_DL_ERROR,
"handle_mp_timer_intr not empty MP timer interrupt and"
" request queues\n"
);
}
rval = service_mp_timer_intr_request(state,timer_interval,cur_mp_time);
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_TRACE,"handle_mp_timer_intr finished\n");
return rval;
}
if (mp_timer_intr_spec -> cur_queue_size >=
mp_timer_intr_spec -> max_queue_size
)
{
mp_timer_intr_spec -> losed_intr_num ++;
mutex_exit(&state->mutex); /* end MUTEX */
return 0;
}
mp_timer_intr = (mp_intr_t *) kmem_alloc(sizeof(mp_intr_t),KM_NOSLEEP);
if (mp_timer_intr == NULL)
{
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_ERROR,
"handle_mp_timer_intr: kmem_alloc no memory is available\n"
);
return 1;
}
mp_timer_intr -> next_mp_intr = NULL;
mp_timer_intr -> intr_num = mp_timer_intr_spec -> total_intr_num;
mp_timer_intr -> timer_interval = timer_interval;
mp_timer_intr -> enqueue_time = cur_mp_time;
if (mp_timer_intr_spec -> mp_intr_queue_start == NULL)
{
mp_timer_intr_spec -> mp_intr_queue_start = mp_timer_intr;
mp_timer_intr_spec -> mp_intr_queue_end = mp_timer_intr;
}
else
{
mp_timer_intr_spec -> mp_intr_queue_end -> next_mp_intr =
mp_timer_intr;
mp_timer_intr_spec -> mp_intr_queue_end = mp_timer_intr;
}
mp_timer_intr_spec -> cur_queue_size ++;
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_TRACE,"handle_mp_timer_intr finished\n");
return rval;
}
/*
* Handle interrupt received from MP after MP timer expiration.
*/
/*ARGSUSED*/
static int handle_mp_timer_intr_request(
mcb_state_t *state,
mp_tm_intr_info_t *mp_timer_intr_info)
{
mp_intr_spec_t * mp_timer_intr_spec = NULL;
int rval = 0;
intr_req_t * mp_timer_intr_request;
u_int request_interval = 0;
#ifdef _MP_TIME_USE_
u_int cur_mp_time = 0;
#else
hrtime_t cur_mp_time = 0;
#endif /* _MP_TIME_USE_ */
drv_intercom_t * drv_communication = NULL;
ME90_LOG(state, ME90_DL_TRACE,"handle_mp_timer_intr_request started\n");
mp_timer_intr_spec = &state -> mp_timer_intrs;
clean_mp_timer_intr_info(mp_timer_intr_info);
mutex_enter(&state->mutex); /* start MUTEX */
if (mp_timer_intr_spec -> mp_intr_mode_on != 1)
{
if (mp_timer_intr_spec -> mp_intr_mode_on == -1)
{
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(NULL, ME90_DL_TRACE,
"handle_mp_timer_intr_request MP timer intr mode"
" was turn off already\n"
);
return 0; /* handuped request after the mode was turn off */
}
else
{
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(NULL, ME90_DL_ERROR,
"handle_mp_timer_intr_request not waiting MP timer"
" interrupt mode\n"
);
return 1;
}
}
drv_communication =
(drv_intercom_t *) &state -> MC_BMEM[TR_CNTR_BUF_BMEM_ADDR];
#ifdef _MP_TIME_USE_
READ_MP_TIME(cur_mp_time = (long)drv_communication);
#else
cur_mp_time = ddi_gethrtime();
#endif /* _MP_TIME_USE_ */
mp_timer_intr_spec -> total_request_num ++;
if (mp_timer_intr_spec -> total_request_num > 1)
#ifdef _MP_TIME_USE_
request_interval =
mckk_calculate_work_time(mp_timer_intr_spec -> last_request_time,
cur_mp_time);
#else
request_interval =
mckk_calculate_work_hr_time(
mp_timer_intr_spec -> last_request_time,
cur_mp_time);
#endif /* _MP_TIME_USE_ */
mp_timer_intr_spec -> last_request_time = cur_mp_time;
if (mp_timer_intr_spec -> cur_queue_size > 0)
{
if (mp_timer_intr_spec -> cur_request_num > 0)
{
ME90_LOG(NULL, ME90_DL_ERROR,
"handle_mp_timer_intr_request not empty MP timer "
" interrupt and request queues\n"
);
}
rval = service_mp_timer_intr(state,
mp_timer_intr_info,
request_interval,
cur_mp_time
);
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_TRACE,"handle_mp_timer_intr_request finished\n");
return rval;
}
mp_timer_intr_request =
(intr_req_t *) kmem_alloc(sizeof(mp_intr_t),KM_NOSLEEP);
if (mp_timer_intr_request == NULL)
{
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_ERROR,
"handle_mp_timer_intr_request: kmem_alloc no memory "
"is available\n"
);
return 1;
}
mp_timer_intr_request -> next_intr_request = NULL;
cv_init(&mp_timer_intr_request -> intr_received_cv);
mp_timer_intr_request -> intr_info = mp_timer_intr_info;
mp_timer_intr_request -> enqueue_time = cur_mp_time;
mp_timer_intr_info -> request_num =
mp_timer_intr_spec -> total_request_num;
mp_timer_intr_info -> request_interval = request_interval;
if (mp_timer_intr_spec -> intr_req_queue_start == NULL)
{
mp_timer_intr_spec -> intr_req_queue_start = mp_timer_intr_request;
mp_timer_intr_spec -> intr_req_queue_end = mp_timer_intr_request;
}
else
{
mp_timer_intr_spec -> intr_req_queue_end -> next_intr_request =
mp_timer_intr_request;
mp_timer_intr_spec -> intr_req_queue_end = mp_timer_intr_request;
}
mp_timer_intr_spec -> cur_request_num ++;
ME90_LOG(state, ME90_DL_TRACE,
"handle_mp_timer_intr_request will be waiting for MP timer\n"
);
cv_wait_sig(&mp_timer_intr_request -> intr_received_cv, &state->mutex);
// cv_spin_wait(&mp_timer_intr_request -> intr_received_cv, &state->lock);
cv_destroy(&mp_timer_intr_request -> intr_received_cv);
kmem_free(mp_timer_intr_request,sizeof(intr_req_t));
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_TRACE,"handle_mp_timer_intr_request finished\n");
return rval;
}
static void clean_mp_timer_intr_info(
mp_tm_intr_info_t * mp_timer_intr_info
)
{
mp_timer_intr_info -> intr_num = 0;
mp_timer_intr_info -> timer_interval = 0;
mp_timer_intr_info -> request_num = 0;
mp_timer_intr_info -> request_interval = 0;
mp_timer_intr_info -> request_enqueued = 0;
mp_timer_intr_info -> waiting_time = 0;
mp_timer_intr_info -> unclaimed_intr_num = 0;
mp_timer_intr_info -> losed_intr_num = 0;
}
/*
* Service first in the list of request waiting for interrupt
* received from MP after MP timer expiration.
*/
/*ARGSUSED*/
static int service_mp_timer_intr_request(
mcb_state_t * state,
u_int timer_interval,
#ifdef _MP_TIME_USE_
u_int intr_receiving_time
#else
hrtime_t intr_receiving_time
#endif /* _MP_TIME_USE_ */
)
{
mp_intr_spec_t * mp_timer_intr_spec = NULL;
intr_req_t * intr_request = NULL;
ME90_LOG(state, ME90_DL_TRACE,"service_mp_timer_intr_request started\n");
mp_timer_intr_spec = &state -> mp_timer_intrs;
intr_request = mp_timer_intr_spec -> intr_req_queue_start;
if (intr_request == NULL)
{
ME90_LOG(state, ME90_DL_ERROR,
"service_mp_timer_intr_request: no request in the queue\n"
);
return 1;
}
mp_timer_intr_spec -> intr_req_queue_start =
intr_request -> next_intr_request;
if (mp_timer_intr_spec -> intr_req_queue_start == NULL)
mp_timer_intr_spec -> intr_req_queue_end = NULL;
mp_timer_intr_spec -> cur_request_num --;
intr_request -> intr_info -> intr_num =
mp_timer_intr_spec -> total_intr_num;
intr_request -> intr_info -> timer_interval = timer_interval;
intr_request -> intr_info -> request_enqueued = 1;
intr_request -> intr_info -> waiting_time =
#ifdef _MP_TIME_USE_
mckk_calculate_work_time(intr_request -> enqueue_time,
intr_receiving_time);
#else
mckk_calculate_work_hr_time(intr_request -> enqueue_time,
intr_receiving_time);
#endif /* _MP_TIME_USE_ */
intr_request -> intr_info -> unclaimed_intr_num =
mp_timer_intr_spec -> cur_queue_size;
intr_request -> intr_info -> losed_intr_num =
mp_timer_intr_spec -> losed_intr_num;
cv_broadcast(&intr_request -> intr_received_cv);
ME90_LOG(state, ME90_DL_TRACE,"service_mp_timer_intr_request successed\n");
return 0;
}
/*
* Service first in the list of MP timer interrupts waiting for request
* from SPARC.
*/
/*ARGSUSED*/
static int service_mp_timer_intr(
mcb_state_t * state,
mp_tm_intr_info_t * mp_timer_intr_info,
u_int request_interval,
#ifdef _MP_TIME_USE_
u_int request_receiving_time
#else
hrtime_t request_receiving_time
#endif /* _MP_TIME_USE_ */
)
{
mp_intr_spec_t * mp_timer_intr_spec = NULL;
mp_intr_t * mp_intrrupt = NULL;
ME90_LOG(state, ME90_DL_TRACE,"service_mp_timer_intr started\n");
mp_timer_intr_spec = &state -> mp_timer_intrs;
mp_intrrupt = mp_timer_intr_spec -> mp_intr_queue_start;
if (mp_intrrupt == NULL)
{
ME90_LOG(state, ME90_DL_ERROR,
"service_mp_timer_intr: no MP interrupts in the queue\n"
);
return 1;
}
mp_timer_intr_spec -> mp_intr_queue_start =
mp_intrrupt -> next_mp_intr;
if (mp_timer_intr_spec -> mp_intr_queue_start == NULL)
mp_timer_intr_spec -> mp_intr_queue_end = NULL;
mp_timer_intr_spec -> cur_queue_size --;
mp_timer_intr_info -> request_num =
mp_timer_intr_spec -> total_request_num;
mp_timer_intr_info -> request_interval = request_interval;
mp_timer_intr_info -> intr_num = mp_intrrupt -> intr_num;
mp_timer_intr_info -> timer_interval = mp_intrrupt -> timer_interval;
mp_timer_intr_info -> request_enqueued = 0;
mp_timer_intr_info -> waiting_time =
#ifdef _MP_TIME_USE_
mckk_calculate_work_time(request_receiving_time,
mp_intrrupt -> enqueue_time);
#else
mckk_calculate_work_hr_time(request_receiving_time,
mp_intrrupt -> enqueue_time);
#endif /* _MP_TIME_USE_ */
mp_timer_intr_info -> unclaimed_intr_num =
mp_timer_intr_spec -> cur_queue_size;
mp_timer_intr_info -> losed_intr_num =
mp_timer_intr_spec -> losed_intr_num;
kmem_free(mp_intrrupt,sizeof(mp_intr_t));
ME90_LOG(state, ME90_DL_TRACE,"service_mp_timer_intr successed\n");
return 0;
}
/*
* Remove queue of pending request. ALL transfers are still waiting for
* device request will be removed
*/
/*ARGSUSED*/
static void remove_drq_queue(
mcb_state_t * state,
int channel
)
{
me90drv_chnl_state_t * channel_state = NULL;
/* buf_t * bp = NULL;*/
drq_trans_spec_t * cur_transfer = NULL;
ME90_LOG(state, ME90_DL_TRACE,"remove_drq_queue channel %d started\n",
channel
);
channel_state = &state -> all_channels_state[channel];
while (channel_state -> drq_queue_start != NULL)
{
cur_transfer = channel_state -> drq_queue_start;
channel_state -> drq_queue_start = cur_transfer -> next_trans_spec;
channel_state -> drq_queue_size --;
ME90_LOG(NULL, ME90_DL_ERROR,
"remove_drq_queue channel %d transfer request removed\n",
channel
);
/* bp = cur_transfer -> bp;
bp->b_resid = bp->b_bcount;
bioerror(bp, EINVAL);
biodone(bp);*/
kmem_free(cur_transfer,sizeof(drq_trans_spec_t));
}
channel_state -> drq_queue_end = NULL;
ME90_LOG(state, ME90_DL_TRACE,"remove_drq_queue channel %d successed\n",
channel
);
}
/*
* Remove hanguped MP timer interrupts and their request
*/
/*ARGSUSED*/
static void remove_mp_timer_intr(mcb_state_t *state)
{
mp_intr_spec_t * mp_timer_intr_spec = NULL;
mp_intr_t * cur_mp_intr = NULL;
intr_req_t * cur_mp_intr_request = NULL;
ME90_LOG(state, ME90_DL_TRACE,"remove_mp_timer_intr started\n");
mp_timer_intr_spec = &state -> mp_timer_intrs;
while (mp_timer_intr_spec -> mp_intr_queue_start != NULL)
{
cur_mp_intr = mp_timer_intr_spec -> mp_intr_queue_start;
mp_timer_intr_spec -> mp_intr_queue_start =
cur_mp_intr -> next_mp_intr;
mp_timer_intr_spec -> cur_queue_size --;
kmem_free(cur_mp_intr,sizeof(mp_intr_t));
}
mp_timer_intr_spec -> mp_intr_queue_end = NULL;
while (mp_timer_intr_spec -> intr_req_queue_start != NULL)
{
cur_mp_intr_request = mp_timer_intr_spec -> intr_req_queue_start;
mp_timer_intr_spec -> intr_req_queue_start =
cur_mp_intr_request -> next_intr_request;
mp_timer_intr_spec -> cur_request_num --;
cv_broadcast(&cur_mp_intr_request -> intr_received_cv);
}
mp_timer_intr_spec -> intr_req_queue_end = NULL;
ME90_LOG(state, ME90_DL_TRACE,"remove_mp_timer_intr successed\n");
}
/*
* Lock the channel for I/O operation, mutex_enter must be done by caller
*/
/*ARGSUSED*/
static int get_channel_state(
mcb_state_t * state,
int channel,
trans_state_t transfer_state
)
{
me90drv_chnl_state_t *channel_state = NULL;
trans_buf_t *new_trans_buf = NULL;
dbgmckk("get_channel_state for channel %d started\n",
channel
);
/*
* if needed conditions are satisfied then set the busy flag
*/
channel_state = &state -> all_channels_state[channel];
new_trans_buf = channel_state -> wait_list_start;
if (channel_state -> busy ||
(new_trans_buf == NULL && !channel_state -> streaming)
)
{
ME90_LOG(state, ME90_DL_TRACE,
"get_channel_state channel %d is busy or empty queue\n",
channel
);
return 1;
}
if (channel_state -> multi_buf_lock != NULL)
{
if (new_trans_buf -> trans_buf_desc.drv_buf_used ||
!new_trans_buf -> multi_buf_flag ||
/* new_trans_buf -> trans_buf_desc.bp !=
channel_state -> multi_buf_lock*/
new_trans_buf -> trans_buf_desc.uio_p !=
channel_state -> multi_buf_lock
)
{
ME90_LOG(state, ME90_DL_TRACE,
"get_channel_state channel %d loccked by multi-"
"buf transfer\n",
channel
);
return 1;
}
}
channel_state -> transfer_state = transfer_state;
channel_state -> busy = 1;
/*
* Drop state state structure
*/
dbgmckk("get_channel_state for channel %d successed\n",
channel
);
return 0;
}
/*
* Driver attach entry point
*/
/*ARGSUSED*/
static int
get_reg_sets_number(
e90_unit_t type_unit,
char get_max_num)
{
int groups_number = 0;
ME90_LOG(NULL, ME90_DL_TRACE,"get_reg_sets_number started\n");
switch (type_unit)
{
case MCKA_UT :
case MCKK_UT :
// case MC19_UT :
case MC53_UT :
case MCPM_UT :
if (get_max_num)
groups_number = MC_MAX_REG_SETS_NUM;
else
groups_number = MC_MIN_REG_SETS_NUM;
break;
default :
ME90_LOG(NULL, ME90_DL_ERROR,
"get_reg_sets_number : bad board type %d\n",
type_unit
);
};
ME90_LOG(NULL, ME90_DL_TRACE,"get_reg_sets_number finished\n");
return groups_number;
}
static void
init_reg_sets_pointers(
mcb_state_t *state,
e90_unit_t type_unit)
{
ME90_LOG(state, ME90_DL_TRACE,"init_reg_sets_pointers started\n");
switch (type_unit)
{
case MCKA_UT :
case MCKK_UT :
// case MC19_UT :
case MC53_UT :
case MCPM_UT :
state -> MC_EPROM_CADDR = NULL;
state -> MC_CNTR_ST_REGS = NULL;
state -> MC_BMEM = NULL;
break;
default :
ME90_LOG(NULL, ME90_DL_ERROR,
"init_reg_sets_pointers : bad board type %d\n",
type_unit
);
}
ME90_LOG(state, ME90_DL_TRACE,"init_reg_sets_pointers finished\n");
}
static int
put_reg_set_pointer(
mcb_state_t *state,
u_int i_reg_gr,
caddr_t regs_mass)
{
int ok = 1;
ME90_LOG(state, ME90_DL_TRACE,"put_reg_set_pointer started\n");
switch (state -> type_unit)
{
case MCKA_UT :
case MCKK_UT :
// case MC19_UT :
case MC53_UT :
case MCPM_UT :
if (i_reg_gr == 0)
{
ME90_LOG(state, ME90_DL_TRACE,"put_reg_set_pointer map EPROM\n");
state -> MC_EPROM_CADDR = regs_mass;
}
else if (i_reg_gr == 1)
{
ME90_LOG(state, ME90_DL_TRACE,"put_reg_set_pointer map GEN_REGS\n");
state -> MC_CNTR_ST_REGS = (mc_cntr_st_reg_t *) regs_mass;
}
else if (i_reg_gr == 2)
{
ME90_LOG(state, ME90_DL_TRACE,"put_reg_set_pointer map BMEM\n");
state -> MC_BMEM = regs_mass;
}
else
{
ME90_LOG(state, ME90_DL_ERROR,
"put_reg_set_pointer : bad MC board reg set num %d\n",
i_reg_gr
);
ok = 0;
};
break;
default :
ME90_LOG(state, ME90_DL_ERROR,
"put_reg_set_pointer : bad board type %d\n",
state -> type_unit
);
ok = 0;
}
ME90_LOG(state, ME90_DL_TRACE,"put_reg_set_pointer finished\n");
return ok;
}
static void
Unmap_reg_sets(mcb_state_t *state)
{
int i_reg_gr = 0;
ME90_LOG(state, ME90_DL_TRACE,"Unmap_reg_sets started\n");
if ( state->MC_EPROM_CADDR != NULL ) {
ME90_LOG(state, ME90_DL_TRACE,
"Unmap_reg_sets unmap EPROM set # %d\n", i_reg_gr);
mckk_iounmap(state, 0, state->MC_EPROM_CADDR);
state->MC_EPROM_CADDR = NULL;
i_reg_gr ++;
}
if ( state->MC_CNTR_ST_REGS != NULL ) {
ME90_LOG(state, ME90_DL_TRACE,
"Unmap_reg_sets unmap GEN_REGS set # %d\n", i_reg_gr);
mckk_iounmap(state, 1, state->MC_CNTR_ST_REGS);
state->MC_CNTR_ST_REGS = NULL;
i_reg_gr ++;
}
if ( state->MC_BMEM != NULL ) {
ME90_LOG(state, ME90_DL_TRACE,
"Unmap_reg_sets unmap BMEM set # %d\n", i_reg_gr);
mckk_iounmap(state, 2, state->MC_BMEM);
state->MC_BMEM = NULL;
i_reg_gr ++;
}
ME90_LOG(state, ME90_DL_TRACE,
"Unmap_reg_sets finished and deleted %d reg sets\n",
i_reg_gr);
} /* No nessesary to unmap reg fields from user */
/*
* Init driver soft state structures to attach driver
*/
static void
mcb_init_drv_state(mcb_state_t *state)
{
int cur_chnl = 0;
ME90_LOG(state, ME90_DL_TRACE, "mckk_init_drv_state started");
state -> cntr_flag_map = 0;
state -> trans_mode_inited = 0;
state -> trans_mode_init_error = 0;
state -> max_cnct_events_num = 0;
state -> cur_cnct_events_num = 0;
state -> losed_events_num = 0;
state -> connection_events = NULL;
state->connection_state = 0;
state->cnct_polling_error = 0;
for ( cur_chnl = 0; cur_chnl < MAX_MC_BOARD_CHANNEL_NUM; cur_chnl++ ) {
me90drv_chnl_state_t *channel_state = NULL;
channel_state = &state -> all_channels_state[cur_chnl];
channel_state -> drq_queue_size = 0;
channel_state -> drq_queue_start = NULL;
channel_state -> drq_queue_end = NULL;
channel_state -> streaming = 0;
channel_state -> multi_buf_lock = NULL;
channel_state -> pseudostreaming = 1;
}
state->mp_timer_intrs.mp_intr_mode_on = 0;
state->mp_timer_intrs.interval = 0;
state->mp_timer_intrs.max_queue_size = 0;
state->mp_timer_intrs.cur_queue_size = 0;
state->mp_timer_intrs.losed_intr_num = 0;
state->mp_timer_intrs.total_intr_num = 0;
state->mp_timer_intrs.last_intr_time = 0;
state->mp_timer_intrs.mp_intr_queue_start = NULL;
state->mp_timer_intrs.mp_intr_queue_end = NULL;
state->mp_timer_intrs.cur_request_num = 0;
state->mp_timer_intrs.total_request_num = 0;
state->mp_timer_intrs.last_request_time = 0;
state->mp_timer_intrs.intr_req_queue_start = NULL;
state->mp_timer_intrs.intr_req_queue_end = NULL;
ME90_LOG(state, ME90_DL_TRACE, "mckk_init_drv_state succeeded");
}
/*
* MC module types driver additional Attachments
*/
/*ARGSUSED*/
static int
mcb_attach_add(
mcb_state_t *state,
int *add_attach_flags)
{
int attach_flags = 0;
/*
* Initialize condition variables of connection polling for this
* instance
*/
cv_init(&state -> cnct_polling_cv);
attach_flags |= CNCT_POLLING_CV_ADDED;
*add_attach_flags = attach_flags;
return 0;
}
/*
* Detach MC module types driver additional Attachments
*/
/*ARGSUSED*/
static void
mcb_detach_add(
mcb_state_t *state,
int add_attach_flags,
int uncondit_detach)
{
if ((add_attach_flags & CNCT_POLLING_CV_ADDED) || uncondit_detach) {
cv_destroy(&state -> cnct_polling_cv);
}
}
#if 0 // NOT USED
/*
* Detach specific for MC types module
* Free additional resources allocated in mckk_attach
*/
/*ARGSUSED*/
static int
mckk_dodetach_add(mcb_state_t *state)
{
int cur_chnl = 0;
ME90_LOG(state, ME90_DL_TRACE,
"mckk_dodetach_add started\n");
for (cur_chnl = 0; cur_chnl < MAX_MC_BOARD_CHANNEL_NUM; cur_chnl ++) {
me90drv_chnl_state_t *channel_state = NULL;
channel_state = &state -> all_channels_state[cur_chnl];
if (channel_state -> multi_buf_lock != NULL)
ME90_LOG(state, ME90_DL_ERROR,
"mckk_dodetach_add: detach busy or with "
"transfers channel %d\n", cur_chnl);
};
/*
* Reset connection polling mode
*/
if ((state -> connection_state & MODE_ON_CONNECTION_STATE) ||
(state -> connection_state & MP_TAKE_CONNECTION_STATE) ||
(state -> connection_state & IS_SET_CONNECTION_STATE) ||
state -> connection_events != NULL ||
state -> max_cnct_events_num > 0)
mcb_reset_connection_polling(state, 0);
ME90_LOG(state, ME90_DL_TRACE,
"mckk_delete_trans_header Driver detached\n");
return DDI_SUCCESS;
}
#endif // NOT USED
/*
* Detect and get the current interrupt reason
*/
static intr_reason_t get_intr_reason(
mcb_state_t * state,
sparc_drv_args_t * interrupt_args,
#ifdef _MP_TIME_USE_
u_int intr_receiving_time
#else
hrtime_t intr_receiving_time
#endif /* _MP_TIME_USE_ */
)
{
int args_num = 0;
int cur_arg = -1;
me90drv_chnl_state_t *channel_state = NULL;
mc_rd_reg_t read_value;
mc_wr_reg_t intr_reset_value;
drv_intercom_t * drv_communication = NULL;
intr_reason_t interrupt_reason = undefined_intr_reason;
int channel = 0;
int retrieve_trans_mode = 0;
int sparc_task[10];
int cur_try = 0;
ME90_LOG(state, ME90_DL_TRACE,"get_intr_reason started\n"); /* !!!!! */
mutex_enter(&state->mutex); /* start MUTEX */
// read_value.RGEN_read = state -> MC_CNTR_ST_REGS -> MC_TI_read;
read_value.RGEN_read = state -> read_value.RGEN_read;
read_value.RERR_read = 0; //alexmipt addition (architecture BUG)
if (read_value.TISB_read == 0) /* our board did not interrupt */
{
if (read_value.RERR_read != 0)
{
if (read_value.TLRM_read == 0)
{
if (state -> mp_state != crash_mp_state)
state -> mp_state = fault_mp_state;
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_TRACE, /* !!!!!!!!!! */
"get_intr_reason interrupt on board error\n"
);
ME90_LOG(state, ME90_DL_ERROR,
"reset module and MP on internal error REER = 0x%x"
" channel %d\n",
read_value.RERR_read,
read_value.RNC_read
);
if (state -> drv_general_modes & RETRIEVE_DEV_FAULT_DRV_MODE)
me90_retrieve_trans_mode(state,0,check_and_do_restart_type,read_value);
ME90_LOG(state, ME90_DL_TRACE, /* !!!!!!!!!! */
"get_intr_reason finished\n"
);
return board_error_intr_reason;
}
}
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_TRACE,"get_intr_reason reject interrupt\n");
return reject_intr_reason;
}
drv_communication =
(drv_intercom_t *) &state -> MC_BMEM[TR_CNTR_BUF_BMEM_ADDR];
args_num = sizeof(drv_communication -> sparc_args.args_area) /
sizeof(*drv_communication -> sparc_args.args_area);
for (cur_arg = 0; cur_arg < args_num; cur_arg ++)
{
interrupt_args -> args_area[cur_arg] =
drv_communication -> sparc_args.args_area[cur_arg];
}
/*
* Interrupt register reset
*/
intr_reset_value.RGEN_write = 0;
state -> MC_CNTR_ST_REGS -> MC_TISB_write = intr_reset_value.RGEN_write;
for (cur_try = 0;
cur_try < sizeof(sparc_task) / sizeof(*sparc_task);
cur_try ++
)
{
sparc_task[cur_try] = drv_communication -> sparc_task;
}
switch (sparc_task[2])
{
case transfer_end_mp_task :
case transfer_halted_mp_task :
case drq_transfer_end_mp_task :
case transfer_abort_end_mp_task :
channel = interrupt_args -> transfer.dev_num;
if (channel >= MAX_MC_BOARD_CHANNEL_NUM || channel < 0)
{
ME90_LOG(state, ME90_DL_ERROR,
"get_intr_reason bad channel # %d from MP\n",
channel
);
interrupt_reason = undefined_intr_reason;
break;
}
channel_state = &state -> all_channels_state[channel];
if (drv_communication -> sparc_task == transfer_halted_mp_task)
{
interrupt_reason = dma_trans_halt_intr_reason;
ME90_LOG(state, ME90_DL_ERROR,
"get_intr_reason channel # %d dma trans halted due to error\n",
channel
);
channel_state -> in_progress = 0;
}
else{
interrupt_reason = dma_trans_end_intr_reason;
}
if ((!channel_state -> busy &&
!(state -> drv_general_modes & MULTI_REQ_CHANNEL_DRV_MODE)) ||
(!channel_state -> busy &&
channel_state -> in_progress_start == NULL &&
(state -> drv_general_modes & MULTI_REQ_CHANNEL_DRV_MODE)))
{
if (channel_state -> transfer_state == timeout_trans_state ||
channel_state -> transfer_state == aborted_trans_state
)
{ /* transfer was aborted or timeout occured */
ME90_LOG(state, ME90_DL_TRACE,
"get_intr_reason: channel %d transfer was aborted or "
"timeout occured\n",
channel
);
interrupt_reason = aborted_intr_reason;
break;
}
else
{
ME90_LOG(state, ME90_DL_ERROR, /*!!!!!!!!*/
"get_intr_reason: interrupt from free channel %d"
" with task %d\n",
channel,
sparc_task[2]
);
interrupt_reason = undefined_intr_reason;
break;
}
}
if (channel_state -> dma_intr_handled)
{
ME90_LOG(state, ME90_DL_ERROR,
"get_intr_reason multi-interrupt for channel # %d\n",
channel
);
interrupt_reason = undefined_intr_reason;
break;
}
else if (!channel_state -> streaming)
channel_state -> dma_intr_handled = 1;
me90drv_handle_trans_finish(state,channel,
&interrupt_args -> transfer,
read_value,
intr_receiving_time,
0 /* trans finished, or aborted */
);
channel_state -> dma_intr_handled = 0;
if (!channel_state -> streaming &&
channel_state -> in_progress_start == NULL)
channel_state -> in_progress = 0;
if (state -> mp_state == adapter_abend_mp_state)
retrieve_trans_mode = 0;
ME90_LOG(state, ME90_DL_TRACE,
"get_intr_reason: DMA channel %d transfer end interrupt "
"detected\n",
channel
); /* !!!!! */
break;
case drq_receive_mp_task :
channel = interrupt_args -> drq.dev_num;
if (channel >= MAX_MC_BOARD_CHANNEL_NUM || channel < 0)
{
ME90_LOG(state, ME90_DL_ERROR,
"get_intr_reason bad DRQ channel # %d from MP\n",
channel
);
interrupt_reason = undefined_intr_reason;
break;
}
interrupt_reason = drq_receive_intr_reason;
break;
case mp_timer_expired_mp_task :
ME90_LOG(state, ME90_DL_TRACE,
"get_intr_reason MP timer interrupt task # %d\n",
drv_communication -> sparc_task
);
interrupt_reason = mp_timer_expired_intr_reason;
break;
case init_trans_mode_end_mp_task :
interrupt_reason = init_trans_mode_end_intr_reason;
break;
case cnct_polling_good_mp_task :
interrupt_reason = cnct_polling_good_intr_reason;
break;
case cnct_polling_bad_mp_task :
interrupt_reason = cnct_polling_bad_intr_reason;
break;
case set_timetable_end_mp_task :
case device_adapter_read_end_mp_task :
case device_adapter_write_end_mp_task :
case halt_trans_mode_end_mp_task :
case init_streaming_end_mp_task :
case init_trans_state_end_mp_task :
case halt_trans_state_end_mp_task :
case no_sparc_task :
case drv_load_end_mp_task :
default:
ME90_LOG(state, ME90_DL_ERROR,
"get_intr_reason undefined interrupt task # %d %d %d %d %d %d %d %d BMEM %d\n",
sparc_task[0],sparc_task[1],sparc_task[2],sparc_task[3],
sparc_task[4],sparc_task[5],sparc_task[6],sparc_task[7],
drv_communication -> sparc_task
);
interrupt_reason = undefined_intr_reason;
break;
}
drv_communication -> sparc_task = no_sparc_task;
mutex_exit(&state->mutex); /* end MUTEX */
if (retrieve_trans_mode &&
(state -> drv_general_modes & RETRIEVE_ADPT_ABEND_DRV_MODE)
)
{
ME90_LOG(state, ME90_DL_ERROR,
"get_intr_reason MP driver must be retrieved\n"
);
me90_retrieve_trans_mode(state,0,0,read_value);
}
ME90_LOG(state, ME90_DL_TRACE,"get_intr_reason finished\n"); /* !!!!! */
return interrupt_reason;
}
/*
* Release the asynchronous transfers resources
*/
/*ARGSUSED*/
static void
mcb_release_async_trans(
mcb_state_t *state,
int channel,
trans_buf_t *trans_buf_p)
{
trans_spec_t *transfer_spec = NULL;
ME90_LOG(state, ME90_DL_TRACE,
"mckk_release_async_trans started for channel %d\n", channel);
if (trans_buf_p -> trans_buf_desc.drv_buf_used &&
trans_buf_p -> drv_buf_p != NULL) {
transfer_spec = (trans_spec_t *)
trans_buf_p -> drv_buf_p -> transfer_spec;
kmem_free(trans_buf_p -> drv_buf_p -> uio_p -> uio_iov,
sizeof(iovec_t));
kmem_free(trans_buf_p -> drv_buf_p -> uio_p, sizeof(uio_t));
trans_buf_p -> drv_buf_p -> uio_p = NULL;
mckk_delete_drv_buf(state, trans_buf_p -> drv_buf_p);
trans_buf_p -> drv_buf_p = NULL;
} else if (trans_buf_p -> trans_buf_desc.uio_p != NULL) {
/* } else if (trans_buf_p -> trans_buf_desc.bp != NULL) {
mckk_buf_trans_done(state, channel,
trans_buf_p -> trans_buf_desc.bp);
transfer_spec = trans_buf_p -> trans_buf_desc.bp -> b_private;
freerbuf(trans_buf_p -> trans_buf_desc.bp);
trans_buf_p ->trans_buf_desc. bp = NULL;*/
mckk_buf_trans_done(state, channel,
trans_buf_p -> trans_buf_desc.uio_p);
transfer_spec = trans_buf_p -> trans_buf_desc.uio_p -> transfer_spec;
/* freerbuf(trans_buf_p -> trans_buf_desc.bp);*/
kmem_free(trans_buf_p -> trans_buf_desc.uio_p -> uio_iov,
sizeof(iovec_t));
kmem_free(trans_buf_p -> trans_buf_desc.uio_p, sizeof(uio_t));
trans_buf_p ->trans_buf_desc. uio_p = NULL;
} else {
if (trans_buf_p -> trans_buf_desc.drv_buf_used) {
ME90_LOG(state, ME90_DL_ERROR,
"mckk_release_async_trans NULL pointer of drv"
" buf in trans buf 0x%x\n", trans_buf_p);
} else {
ME90_LOG(state, ME90_DL_ERROR,
"mckk_release_async_trans NULL pointer of bp"
" in trans buf 0x%x\n", trans_buf_p);
}
}
if (transfer_spec != NULL) {
if (transfer_spec -> trans_res_info != NULL)
kmem_free(transfer_spec -> trans_res_info,
sizeof(trans_info_t));
kmem_free(transfer_spec, sizeof(trans_spec_t));
}
me90drv_delete_trans_header(state, trans_buf_p);
ME90_LOG(state, ME90_DL_TRACE,
"mckk_release_async_trans finished for channel %d\n", channel);
}
/*
* The DMA data transfer engine start
*/
/*ARGSUSED*/
static int
start_mckk_dma_engine(
mcb_state_t *state,
int channel
/* int flags*/)
{
me90drv_chnl_state_t * channel_state = &state -> all_channels_state[channel];
/* buf_t * bp = NULL;*/
uio_t *uio_p = NULL;
mcb_drv_buf_t * drv_buf_p = NULL;
trans_spec_t * transfer_spec = NULL;
trans_info_t * trans_res_info = NULL;
trans_buf_t * cur_trans_buf = NULL;
caddr_t trans_base_addr = 0;
size_t trans_buf_size = 0;
int allowed_burst = 0;
int used_burst = 0;
int io_mode = 0;
int op_flags = 0;
mp_drv_args_t transfer_args;
int dev_access_mode = 0;
int rval = 0;
ME90_LOG(state, ME90_DL_TRACE,"start_mckk_dma_engine started for channel %d\n",
channel
);
mutex_enter(&state->mutex); /* start MUTEX */
cur_trans_buf = channel_state -> in_progress_start;
mutex_exit(&state->mutex); /* end MUTEX */
if (cur_trans_buf == NULL)
return EMPRESTART;
if (!cur_trans_buf -> trans_buf_desc.drv_buf_used)
{
/* bp = cur_trans_buf -> trans_buf_desc.bp;
transfer_spec = bp -> b_private;
trans_base_addr = bp -> b_un.b_addr;
trans_buf_size = bp -> b_bcount;*/
uio_p = cur_trans_buf -> trans_buf_desc.uio_p;
transfer_spec = uio_p -> transfer_spec;
trans_base_addr = uio_p->uio_iov[0].iov_base;
trans_buf_size = uio_p->uio_iov[0].iov_len;
}
else
{
drv_buf_p = cur_trans_buf -> drv_buf_p;
if (drv_buf_p != NULL)
transfer_spec = drv_buf_p -> transfer_spec;
trans_base_addr = cur_trans_buf -> trans_buf_desc.buf_address;
trans_buf_size = cur_trans_buf -> trans_buf_desc.buf_size;
}
rval = mckk_get_burst_sizes(state,
channel_state,
transfer_spec,
trans_base_addr,
trans_buf_size,
&allowed_burst
);
if (rval != 0)
{
ME90_LOG(NULL, ME90_DL_TRACE,
"start_mckk_dma_engine channel %d mckk_get_burst_sizes"
" failed\n",
channel
);
return rval;
}
if (transfer_spec != NULL)
trans_res_info = transfer_spec -> trans_res_info;
if (allowed_burst & DMA_BURST_SIZE_64_BYTES)
{
allowed_burst = DMA_BURST_SIZE_64_BYTES;
used_burst = MCB_64_BURTS_SIZE_CODE;
}
else if (allowed_burst & DMA_BURST_SIZE_32_BYTES)
{
allowed_burst = DMA_BURST_SIZE_32_BYTES;
used_burst = MCB_32_BURTS_SIZE_CODE;
}
else if (allowed_burst & DMA_BURST_SIZE_16_BYTES)
{
allowed_burst = DMA_BURST_SIZE_16_BYTES;
used_burst = MCB_16_BURTS_SIZE_CODE;
}
else if (allowed_burst & DMA_BURST_SIZE_8_BYTES)
{
allowed_burst = DMA_BURST_SIZE_8_BYTES;
used_burst = MCB_8_BURTS_SIZE_CODE;
}
else if (allowed_burst & DMA_BURST_SIZE_4_BYTES)
{
allowed_burst = DMA_BURST_SIZE_4_BYTES;
used_burst = MCB_4_BURTS_SIZE_CODE;
}
else
{
ME90_LOG(state, ME90_DL_ERROR,
"start_mckk_dma_engine - cannot find right burst size for"
" transfer: allowed 0x%02x & enable 0x%02x & address"
" 0x%08x\n",
allowed_burst,MCB_ENABLE_BURST_SIZES,
trans_base_addr
);
return EINVAL;
};
if (transfer_spec != NULL)
{
if (trans_res_info != NULL)
trans_res_info -> burst_byte_size = allowed_burst;
io_mode = transfer_spec -> io_mode_flags;
}
else
io_mode = 0;
if ((((long) trans_base_addr & (allowed_burst-1)) != 0 ||
trans_buf_size % allowed_burst != 0
) &&
!(io_mode & ONLY_UNBUF_IO_MODE)
)
{
ME90_LOG(state, ME90_DL_ERROR,
"start_mckk_dma_engine - bad I/O address and size alignment"
" burst sizes 0x%x bytes, address 0x%lx size 0x%x\n",
allowed_burst,
(u_long) trans_base_addr,
trans_buf_size
);
return EINVAL;
};
ME90_LOG(state, ME90_DL_TRACE,
"start_mckk_dma_engine transaction burst size %d bytes\n",
allowed_burst
);
/*
* Write information about DMA transfer for MP driver
*/
/* if (bp != NULL)
op_flags = bp -> b_flags;*/
if (uio_p != NULL)
op_flags = uio_p->op_flags;
else if (drv_buf_p != NULL)
op_flags = drv_buf_p -> op_flags;
else if (channel_state -> streaming)
op_flags = B_READ;
else
{
ME90_LOG(state, ME90_DL_ERROR,
"start_mckk_dma_engine - bad I/O operation for channel %d\n",
channel
);
return EINVAL;
}
if (op_flags & B_READ)
transfer_args.transfer.opcode = read_trans_opcode;
else if ( op_flags & B_WRITE)
transfer_args.transfer.opcode = write_trans_opcode;
else
{
ME90_LOG(state, ME90_DL_ERROR,
"start_mckk_dma_engine - bad I/O operation b_flags 0x%x",
op_flags
);
return EINVAL;
}
dbgmckk("start_mckk_dma_engine: transfer_args.transfer.opcode = 0x%x\n", transfer_args.transfer.opcode);
if (state -> drv_general_modes & DATA_CACHE_FLUSH_DRV_MODE) {
u_int *os_code_p = (u_int *)0xf0040000;
int cur_word = 0;
u_int the_word = 0;
for (cur_word = 0; cur_word < 1024; cur_word ++) {
the_word |= os_code_p[cur_word * 8];
}
ME90_LOG(state, ME90_DL_TRACE,
"start_mckk_dma_engine - data cache flush has been done"
" by driver, cache word summary 0x%08x\n", the_word);
}
transfer_args.transfer.dev_num = channel;
dbgmckk("start_mckk_dma_engine: transfer_args.transfer.dev_num = 0x%x\n", transfer_args.transfer.dev_num);
transfer_args.transfer.burst_size = used_burst;
dbgmckk("start_mckk_dma_engine: transfer_args.transfer.burst_size = 0x%x\n", transfer_args.transfer.burst_size);
/* transfer_args.transfer.address = cur_trans_buf -> trans_buf_desc.cookie.dmac_address;*/
transfer_args.transfer.address = (u_int)cur_trans_buf -> trans_buf_desc.dma.prim_dev_mem;
dbgmckk("start_mckk_dma_engine: transfer_args.transfer.address = 0x%x\n", transfer_args.transfer.address);
transfer_args.transfer.size = cur_trans_buf -> trans_size;
dbgmckk("start_mckk_dma_engine: transfer_args.transfer.size = 0x%x\n", transfer_args.transfer.size);
if (transfer_spec == NULL)
{
transfer_args.transfer.repeation_num = 1;
transfer_args.transfer.mode = dma_trans_mode;
dev_access_mode = DIRECT_DEV_ACCESS_MODE;
}
else
{
transfer_args.transfer.repeation_num = transfer_spec -> repeation_num;
if (transfer_spec -> io_mode_flags & DMA_TRANSFER_IO_MODE)
transfer_args.transfer.mode = dma_trans_mode;
else if (transfer_spec -> io_mode_flags & PROG_TRANSFER_IO_MODE)
transfer_args.transfer.mode = progr_trans_mode;
else if (transfer_spec -> io_mode_flags & PROG1_TRANSFER_IO_MODE)
transfer_args.transfer.mode = progr1_trans_mode;
else if (transfer_spec -> io_mode_flags & BMEM_TRANSFER_IO_MODE)
transfer_args.transfer.mode = only_bmem_trans_mode;
else
{
ME90_LOG(state, ME90_DL_ERROR,
"start_mckk_dma_engine - bad I/O transfer mode 0x%x\n",
transfer_spec -> io_mode_flags
);
return EINVAL;
}
dev_access_mode = transfer_spec -> dev_access_mode;
}
dbgmckk("start_mckk_dma_engine: transfer_args.transfer.repeation_num = 0x%x\n", transfer_args.transfer.repeation_num);
dbgmckk("start_mckk_dma_engine: transfer_args.transfer.mode = 0x%x\n", transfer_args.transfer.mode);
if (dev_access_mode == DIRECT_DEV_ACCESS_MODE ||
dev_access_mode == ON_DEMAND_DEV_ACCESS_MODE
)
rval = submit_mp_task(state,data_transfer_mp_task,&transfer_args,0,
trans_res_info,
NULL,
0
);
else if (dev_access_mode == WITH_DEMAND_DEV_ACCESS_MODE)
rval = submit_mp_task(state,drq_data_transfer_mp_task,&transfer_args,0,
trans_res_info,
NULL,
0
);
else
{
ME90_LOG(state, ME90_DL_ERROR,
"start_mckk_dma_engine - bad I/O device access mode 0x%x\n",
dev_access_mode
);
return EINVAL;
}
ME90_LOG(state, ME90_DL_TRACE,"start_mckk_dma_engine finished for channel %d\n",
channel
);
return rval;
}
/*
* Set the transfer results in accordance with info in transfer buffer header
*/
/*ARGSUSED*/
static int mckk_set_dma_trans_results(
mcb_state_t * state,
int channel,
trans_buf_t * trans_buf_p,
trans_spec_t * transfer_spec,
size_t moved_data_size
)
{
#ifdef _MP_TIME_USE_
drv_intercom_t *drv_communication = NULL;
#endif /* _MP_TIME_USE_ */
trans_info_t * trans_res_info = NULL;
ME90_LOG(state, ME90_DL_TRACE,
"mckk_set_dma_trans_results started for channel %d trans_buf 0x%08x"
" trans_spec 0x%08x\n",
channel,
trans_buf_p,
transfer_spec
);
#ifdef _MP_TIME_USE_
drv_communication =
(drv_intercom_t *) &state -> MC_BMEM[TR_CNTR_BUF_BMEM_ADDR];
#endif /* _MP_TIME_USE_ */
if (transfer_spec == NULL)
return trans_buf_p -> trans_error;
trans_res_info = transfer_spec -> trans_res_info;
if (trans_res_info == NULL)
return trans_buf_p -> trans_error;
trans_res_info -> trans_errno = trans_buf_p -> trans_error;
if (!trans_buf_p -> pseudobuf)
{
if (moved_data_size == -1)
trans_res_info -> real_byte_size += trans_buf_p -> real_trans_size;
else
{
trans_res_info -> real_byte_size += moved_data_size;
trans_buf_p -> buf_offset += moved_data_size;
}
}
else
trans_res_info -> missed_data_size += trans_buf_p -> real_trans_size;
if (trans_res_info -> mp_error_code == 0)
trans_res_info -> mp_error_code = trans_buf_p -> mp_error_code;
if (trans_res_info -> state_byte == 0)
trans_res_info -> state_byte = trans_buf_p -> board_state_byte;
if (trans_res_info -> sp_state_byte == 0)
trans_res_info -> sp_state_byte = trans_buf_p -> sp_state_byte;
if (trans_res_info -> board_error_code == 0)
trans_res_info -> board_error_code =
trans_buf_p -> gen_reg_state.RERR_read;
trans_res_info -> trans_num = trans_buf_p -> trans_num;
trans_res_info -> intr_transfer_end = trans_buf_p -> intr_transfer_end;
#ifdef _MP_TIME_USE_
READ_MP_TIME(trans_res_info -> transfer_finish);
#else
trans_res_info -> transfer_finish = ddi_gethrtime();
#endif /* _MP_TIME_USE_ */
ME90_LOG(state, ME90_DL_TRACE,
"mckk_set_dma_trans_results successed for channel %d trans_buf 0x%08x"
" trans_spec 0x%08x\n",
channel,
trans_buf_p,
transfer_spec
);
return trans_buf_p -> trans_error;
}
/*
* Set connection polling mode for MP driver
*/
/*ARGSUSED*/
static int mcb_set_connection_polling(
mcb_state_t *state,
cnct_poll_set_t *polling_setup_spec)
{
mp_drv_args_t set_polling_args;
clock_t cur_clock_ticks = 0;
clock_t timeout_clock_ticks = 0;
clock_t setup_waiting_time = 0;
int rval = 0;
ME90_LOG(state, ME90_DL_TRACE,"mckk_set_connection_polling started "
"interval %d cpu %d\n",
polling_setup_spec -> interval,
polling_setup_spec -> cpu_polling
);
mutex_enter(&state->mutex); /* start MUTEX */
if (state -> connection_state & MODE_ON_CONNECTION_STATE)
{
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_ERROR,
"mckk_set_connection_polling polling mode is set already\n"
);
return EINVAL;
}
state -> connection_state = MODE_ON_CONNECTION_STATE;
state -> cnct_polling_error = 0;
if (polling_setup_spec -> connection_events_num > 0)
{
if (state -> max_cnct_events_num > 0 ||
state -> connection_events != NULL
)
{
ME90_LOG(state, ME90_DL_ERROR,
"mckk_set_connection_polling events buffer is created"
" already\n"
);
}
else
{
state -> connection_events =
kmem_alloc(polling_setup_spec -> connection_events_num *
sizeof(poll_event_info_t),
KM_NOSLEEP
);
if (state -> connection_events == NULL)
{
ME90_LOG(state, ME90_DL_ERROR,
"mckk_set_connection_polling cannot allocate kernel"
" memory for events buffer\n"
);
mutex_exit(&state->mutex); /* end MUTEX */
return EINVAL;
}
state -> max_cnct_events_num =
polling_setup_spec -> connection_events_num;
state -> cur_cnct_events_num = 0;
state -> losed_events_num = 0;
}
}
mutex_exit(&state->mutex); /* end MUTEX */
if (polling_setup_spec -> interval == 0)
set_polling_args.set_cnct_polling.interval = CNCT_POLLING_INTERVAL_DEF;
else
set_polling_args.set_cnct_polling.interval =
polling_setup_spec -> interval;
set_polling_args.set_cnct_polling.interval =
set_polling_args.set_cnct_polling.interval / me90_mp_nsec_cycle * 1000;
set_polling_args.set_cnct_polling.cpu_polling =
polling_setup_spec -> cpu_polling;
rval = submit_mp_task(state,set_cnct_polling_mp_task,
&set_polling_args,
0,
NULL,
NULL,
0
);
mutex_enter(&state->mutex); /* start MUTEX */
if (rval != 0)
{
me90drv_delete_connection_polling(state, rval);
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_ERROR,
"mckk_set_connection_polling: mp task failed\n"
);
return rval;
}
state -> connection_state |= MP_TAKE_CONNECTION_STATE;
setup_waiting_time = polling_setup_spec -> setup_timeout;
if (setup_waiting_time == 0)
{
if ((state -> connection_state & IS_SET_CONNECTION_STATE) &&
(state -> connection_state & MODE_ON_CONNECTION_STATE)
)
rval = 0;
else
rval = ETIME;
mutex_exit(&state->mutex); /* end MUTEX */
return rval;
}
if (setup_waiting_time != -1)
{
drv_getparm(LBOLT,(u_long *) &cur_clock_ticks);
timeout_clock_ticks =
cur_clock_ticks + drv_usectohz(setup_waiting_time * 1000);
}
rval = 0;
while ((state -> connection_state & (IS_SET_CONNECTION_STATE |
MODE_OFF_CONNECTION_STATE |
IS_RESET_CONNECTION_STATE
)
) == 0 &&
(state -> connection_state & MODE_ON_CONNECTION_STATE)
)
{
if (setup_waiting_time != -1)
rval = cv_timedwait(&state -> cnct_polling_cv,
&state->mutex,
timeout_clock_ticks
);
else
rval = cv_wait_sig(&state -> cnct_polling_cv, &state->mutex);
// rval = cv_spin_wait(&state -> cnct_polling_cv, &state->lock);
if (rval < 0)
{
rval = ETIME;
ME90_LOG(state, ME90_DL_TRACE,
"set connection polling: waiting for comity connection"
" timeouted\n"
);
break;
}
else if (rval == 0)
{
rval = EINTR;
ME90_LOG(state, ME90_DL_TRACE,
"set connection polling: waiting for comity connection"
" interrupted\n"
);
break;
}
else
rval = 0;
}
if (rval != 0)
{
mutex_exit(&state->mutex); /* end MUTEX */
mcb_reset_connection_polling(state, rval);
ME90_LOG(state, ME90_DL_TRACE,"mckk_set_connection_polling finished with"
" reset connection\n"
);
return rval;
}
if ((state -> connection_state & IS_SET_CONNECTION_STATE) &&
(state -> connection_state & MODE_ON_CONNECTION_STATE)
)
rval = 0;
else if ((state -> connection_state & IS_RESET_CONNECTION_STATE) ||
(state -> connection_state & MODE_OFF_CONNECTION_STATE) ||
!(state -> connection_state & MODE_ON_CONNECTION_STATE)
)
{
ME90_LOG(state, ME90_DL_ERROR,
"mckk_set_connection_polling finished with bad connection state"
" 0x%x\n",
state -> connection_state
);
rval = EINVAL;
}
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_TRACE,"mckk_set_connection_polling finished \n");
return rval;
}
/*
* Reset connection polling mode for MP driver
*/
/*ARGSUSED*/
static int mcb_reset_connection_polling(
mcb_state_t *state,
int reset_error)
{
int rval = 0;
ME90_LOG(state, ME90_DL_TRACE,"mckk_reset_connection_polling started \n");
mutex_enter(&state->mutex); /* start MUTEX */
if (!(state -> connection_state & MODE_ON_CONNECTION_STATE))
{
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_ERROR,
"mckk_reset_connection_polling polling mode is reset already\n"
);
return EINVAL;
}
if (state -> connection_state & MP_TAKE_CONNECTION_STATE)
{
mutex_exit(&state->mutex); /* end MUTEX */
rval = submit_mp_task(state,reset_cnct_polling_mp_task,
NULL,
0,
NULL,
NULL,
0
);
mutex_enter(&state->mutex); /* start MUTEX */
if (rval != 0)
{
ME90_LOG(state, ME90_DL_ERROR,
"mckk_reset_connection_polling: mp task failed\n"
);
}
else
{
state -> connection_state &= ~MP_TAKE_CONNECTION_STATE;
if (state -> connection_state & IS_SET_CONNECTION_STATE)
{
state -> connection_state &= ~IS_SET_CONNECTION_STATE;
state -> connection_state |= IS_RESET_CONNECTION_STATE;
}
}
}
if (reset_error != 0)
rval = reset_error;
me90drv_delete_connection_polling(state, rval);
if (state -> max_cnct_events_num > 0 || state -> connection_events != NULL)
{
kmem_free(state -> connection_events,
state -> max_cnct_events_num * sizeof(poll_event_info_t)
);
state -> connection_events = NULL;
state -> max_cnct_events_num = 0;
state -> cur_cnct_events_num = 0;
state -> losed_events_num = 0;
}
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_TRACE,"mckk_reset_connection_polling finished \n");
return rval;
}
/*
* Wait for connection state change and when connection polling will detect
* errors, then return the refusal to the caller
*/
/*ARGSUSED*/
static int mcb_poll_connection_state(
mcb_state_t *state,
poll_cnct_state_t *state_spec) /* requested connection state */
{
int rval = 0;
int state_mask = state_spec -> state_mask;
int rstate_mask = 0;
clock_t cur_clock_ticks = 0;
clock_t timeout_clock_ticks = 0;
clock_t waiting_time = 0;
ME90_LOG(state, ME90_DL_TRACE,"mckk_poll_connection_state started\n");
mutex_enter(&state->mutex); /* start MUTEX */
if (state_mask == 0)
{
state_spec -> rstate_mask = state -> connection_state;
if (state_spec -> time_info != NULL)
{
state_spec -> time_info -> alive_intr = state -> alive_intr_time;
state_spec -> time_info -> refused_intr = state -> refused_intr_time;
state_spec -> time_info -> drv_return = ddi_gethrtime();
}
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_TRACE,
"mckk_poll_connection_state polling mode with empty state mask\n"
);
return 0;
}
if (!(state -> connection_state & MODE_ON_CONNECTION_STATE) ||
(state -> connection_state & MODE_OFF_CONNECTION_STATE)
)
{
state_spec -> rstate_mask = state -> connection_state;
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_TRACE,
"mckk_poll_connection_state polling mode is not set\n"
);
return EINTR;
}
waiting_time = state_spec -> timeout;
if (waiting_time == 0)
{
rstate_mask = state -> connection_state & state_mask;
if (rstate_mask == 0)
{
if (!(state -> connection_state & MODE_ON_CONNECTION_STATE) ||
(state -> connection_state & MODE_OFF_CONNECTION_STATE)
)
rval = EINTR;
else
rval = ETIME;
rstate_mask = state -> connection_state;
}
else
rval = 0;
state_spec -> rstate_mask = rstate_mask;
if (state_spec -> time_info != NULL)
{
state_spec -> time_info -> alive_intr = state -> alive_intr_time;
state_spec -> time_info -> refused_intr = state -> refused_intr_time;
state_spec -> time_info -> drv_return = ddi_gethrtime();
}
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_TRACE,
"mckk_poll_connection_state null waiting time\n"
);
return rval;
}
if (waiting_time != -1)
{
drv_getparm(LBOLT,(u_long *) &cur_clock_ticks);
timeout_clock_ticks =
cur_clock_ticks + drv_usectohz(waiting_time * 1000);
}
rval = 0;
while ((state_mask & state -> connection_state) == 0 &&
(state -> connection_state & MODE_ON_CONNECTION_STATE) &&
!(state -> connection_state & MODE_OFF_CONNECTION_STATE)
)
{
if (waiting_time != -1)
rval = cv_timedwait(&state -> cnct_polling_cv,
&state->mutex,
timeout_clock_ticks
);
else
rval = cv_wait_sig(&state -> cnct_polling_cv, &state->mutex);
// rval = cv_spin_wait(&state -> cnct_polling_cv, &state->lock);
if (rval < 0)
{
rval = ETIME;
ME90_LOG(state, ME90_DL_TRACE,
"mckk_poll_connection_state: waiting for state"
" timeouted\n"
);
break;
}
else if (rval == 0)
{
rval = EINTR;
ME90_LOG(state, ME90_DL_TRACE,
"mckk_poll_connection_state: waiting for state"
" interrupted\n"
);
break;
}
else
rval = 0;
}
rstate_mask = state -> connection_state & state_mask;
if (rval != 0)
{
rstate_mask = state -> connection_state;
}
else if (!(state -> connection_state & MODE_ON_CONNECTION_STATE) ||
(state -> connection_state & MODE_OFF_CONNECTION_STATE)
)
{
if (rstate_mask == 0)
{
rstate_mask = state -> connection_state;
rval = EINTR;
}
}
state_spec -> rstate_mask = rstate_mask;
if (state_spec -> time_info != NULL)
{
state_spec -> time_info -> alive_intr = state -> alive_intr_time;
state_spec -> time_info -> refused_intr = state -> refused_intr_time;
state_spec -> time_info -> drv_return = ddi_gethrtime();
}
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_TRACE,"mckk_poll_connection_state finished \n");
return rval;
}
/*
* Handler of interrupt from connecton polling service of MP driver
*/
/*ARGSUSED*/
static void mckk_connection_polling_intr(
mcb_state_t * state,
int connection_refused,
hrtime_t intr_receiving_time
)
{
int connection_state = 0;
poll_event_info_t *cur_events_info = NULL;
ME90_LOG(state, ME90_DL_TRACE,"mckk_connection_polling_intr started \n");
mutex_enter(&state->mutex); /* start MUTEX */
connection_state = state -> connection_state;
if (state -> connection_events != NULL)
{
if (state -> cur_cnct_events_num < state -> max_cnct_events_num)
cur_events_info =
&state -> connection_events[state -> cur_cnct_events_num];
else
state -> losed_events_num ++;
}
if (!(connection_state & MODE_ON_CONNECTION_STATE))
{
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_ERROR,
"mckk_connection_polling_intr polling is not set\n"
);
return;
}
if (connection_state & IS_SET_CONNECTION_STATE)
{
if (!connection_refused)
{
if (connection_state & ALIVE_CONNECTION_STATE)
{
state -> alive_intr_time = intr_receiving_time;
if (cur_events_info != NULL)
{
cur_events_info -> event = cpu_alive_poll_event_code;
cur_events_info -> time = intr_receiving_time;
state -> cur_cnct_events_num ++;
}
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_TRACE,
"mckk_connection_polling_intr good state continues\n"
);
return;
}
else if (connection_state & REFUSED_CONNECTION_STATE)
{
state -> connection_state &= ~REFUSED_CONNECTION_STATE;
state -> connection_state |= ALIVE_CONNECTION_STATE;
state -> alive_intr_time = intr_receiving_time;
if (cur_events_info != NULL)
{
cur_events_info -> event = recovered_poll_event_code;
cur_events_info -> time = intr_receiving_time;
state -> cur_cnct_events_num ++;
}
ME90_LOG(state, ME90_DL_TRACE,
"mckk_connection_polling_intr recovery of alive state\n"
);
}
else
{
ME90_LOG(state, ME90_DL_ERROR,
"mckk_connection_polling_intr invalid state # 1\n"
);
return;
}
}
else if (connection_state & ALIVE_CONNECTION_STATE)
{
state -> connection_state &= ~ALIVE_CONNECTION_STATE;
state -> connection_state |= REFUSED_CONNECTION_STATE;
state -> refused_intr_time = intr_receiving_time;
if (cur_events_info != NULL)
{
cur_events_info -> event = refused_poll_event_code;
cur_events_info -> time = intr_receiving_time;
state -> cur_cnct_events_num ++;
}
ME90_LOG(state, ME90_DL_TRACE,
"mckk_connection_polling_intr goto connection refused state\n"
);
}
else if (connection_state & REFUSED_CONNECTION_STATE)
{
state -> refused_intr_time = intr_receiving_time;
if (cur_events_info != NULL)
{
cur_events_info -> event = refused_poll_event_code;
cur_events_info -> time = intr_receiving_time;
state -> cur_cnct_events_num ++;
}
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_TRACE,
"mckk_connection_polling_intr refused state continues\n"
);
return;
}
else
{
ME90_LOG(state, ME90_DL_ERROR,
"mckk_connection_polling_intr invalid state # 2\n"
);
return;
}
}
else
{
if (!connection_refused)
{
state -> connection_state &= ~IS_RESET_CONNECTION_STATE;
state -> connection_state |= IS_SET_CONNECTION_STATE;
state -> connection_state &= ~REFUSED_CONNECTION_STATE;
state -> connection_state |= ALIVE_CONNECTION_STATE;
state -> alive_intr_time = intr_receiving_time;
if (cur_events_info != NULL)
{
cur_events_info -> event = is_set_poll_event_code;
cur_events_info -> time = intr_receiving_time;
state -> cur_cnct_events_num ++;
}
ME90_LOG(state, ME90_DL_TRACE,
"mckk_connection_polling_intr initial connection is set\n"
);
}
else
{
if (cur_events_info != NULL)
{
cur_events_info -> event = interrupted_poll_event_code;
cur_events_info -> time = intr_receiving_time;
state -> cur_cnct_events_num ++;
}
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_TRACE,
"mckk_connection_polling_intr initial connection setting"
" interrupted\n"
);
return;
}
}
cv_broadcast(&state -> cnct_polling_cv);
mutex_exit(&state->mutex); /* end MUTEX */
ME90_LOG(state, ME90_DL_TRACE,"mckk_connection_polling_intr finished \n");
return;
}
/*
* Recover all needed setup, state and mode to start transfers,
*/
/*ARGSUSED*/
int
mcb_recover_trans_state(
mcb_state_t *state,
int drv_comm_area_locked,
int mutex_locked)
{
int rval = 0;
ME90_LOG(state, ME90_DL_TRACE,"mckk_recover_trans_state started \n");
ME90_LOG(state, ME90_DL_TRACE, "mckk_recover_trans_state finished\n");
return rval;
}
/*
* Set the transfer results field in the initial state
*/
/*ARGSUSED*/
static void mckk_init_trans_results(
trans_spec_t * transfer_spec
)
{
trans_info_t * trans_res_info = NULL;
ME90_LOG(NULL, ME90_DL_TRACE,
"mckk_init_trans_results started for trans_spec 0x%lx\n",
transfer_spec
);
if (transfer_spec != NULL)
{
trans_res_info = transfer_spec -> trans_res_info;
if (trans_res_info != NULL)
{
trans_res_info -> trans_errno = 0;
trans_res_info -> trans_num = 0;
trans_res_info -> board_error_code = 0;
trans_res_info -> burst_byte_size = 0;
trans_res_info -> real_byte_size = 0;
trans_res_info -> intr_transfer_end = -1;
trans_res_info -> transfer_start = -1;
trans_res_info -> transfer_finish = -1;
trans_res_info -> mp_error_code = 0;
trans_res_info -> state_byte = 0;
trans_res_info -> sp_state_byte = 0;
trans_res_info -> channel_check_word = 0;
trans_res_info -> missed_data_size = 0;
trans_res_info -> intr_drq_received = -1;
}
}
ME90_LOG(NULL, ME90_DL_TRACE,
"mckk_init_trans_results successed for trans_spec 0x%lx\n",
transfer_spec
);
}
/*
* MP-driver Interrupts handler
*/
//int
static irqreturn_t
mckk_intr_thread_handler(int irq, void *arg)
{
mcb_state_t * state = (mcb_state_t *)arg;
me90drv_chnl_state_t * channel_state = NULL;
intr_reason_t intr_reason = undefined_intr_reason;
sparc_drv_args_t interrupt_args;
int channel = 0;
drv_intercom_t * drv_communication = NULL;
#ifdef _MP_TIME_USE_
u_int intr_receiving_time = 0;
#else
hrtime_t intr_receiving_time;
#endif /* _MP_TIME_USE_ */
#if 0
daemonize("mckk_intr_handlerd");
do
{
waiting_mode:
ME90_LOG(state, ME90_DL_TRACE, "MCKK: waiting for interrupt, in_interrupt = %ld !!!!\n", in_interrupt());
current->policy = SCHED_FIFO;
interruptible_sleep_on(&state->state_mckk_intr_handler);
if (state->waking_up_mckk_intr_handler == 1){
ME90_LOG(state, ME90_DL_TRACE, "waking_up_mckk_intr_handler !!!\n");
state->waking_up_mckk_intr_handler = 0;
break;
}
if (state->state_mckk_intr_handler_shutdown == 1){
ME90_LOG(state, ME90_DL_TRACE, "MCKK: exit by signal\n");
state->state_mckk_intr_handler_shutdown = 0;
return 0;
}
} while (1);
#endif
#ifndef _MP_TIME_USE_
intr_receiving_time = ddi_gethrtime();
#endif
drv_communication =
(drv_intercom_t *) &state -> MC_BMEM[TR_CNTR_BUF_BMEM_ADDR];
#ifdef _MP_TIME_USE_
READ_MP_TIME(intr_receiving_time);
#endif /* _MP_TIME_USE_ */
ME90_LOG(state, ME90_DL_TRACE,"mckk_intr started\n"); /* !!!!! */
intr_reason = get_intr_reason(state,&interrupt_args,intr_receiving_time);
switch (intr_reason)
{
case reject_intr_reason:
ME90_LOG(state, ME90_DL_TRACE,"mckk_intr reject interrupt\n");
return IRQ_HANDLED;
// goto waiting_mode;
case dma_trans_end_intr_reason :
case dma_trans_halt_intr_reason :
channel = interrupt_args.transfer.dev_num;
ME90_LOG(state, ME90_DL_TRACE,
"mckk_intr takes DMA channel %d transfer end interrupt\n",
channel
); /* !!!!! */
channel_state = & state -> all_channels_state[channel];
mckk_terminate_dma_trans(state,channel);
if (!channel_state -> streaming)
me90drv_start_new_trans(state,channel);
ME90_LOG(state, ME90_DL_TRACE,
"mckk_intr DMA channel %d transfer end interrupt claimed\n",
channel
); /* !!!!! */
return IRQ_HANDLED;
// goto waiting_mode;
case drq_receive_intr_reason :
channel = interrupt_args.drq.dev_num;
ME90_LOG(state, ME90_DL_TRACE,
"mckk_intr received DRQ from channel %d interrupt\n",
channel
);
start_pending_transfer(state,channel,intr_receiving_time);
return IRQ_HANDLED;
// goto waiting_mode;
case board_error_intr_reason :
ME90_LOG(state, ME90_DL_TRACE,
"mckk_intr - board internal error interrupt reason\n"
);
return IRQ_HANDLED;
// goto waiting_mode;
case mp_timer_expired_intr_reason :
ME90_LOG(state, ME90_DL_TRACE,"mckk_intr MP timer expired interrupt\n");
handle_mp_timer_intr(state,intr_receiving_time);
return IRQ_HANDLED;
// goto waiting_mode;
case aborted_intr_reason :
ME90_LOG(state, ME90_DL_TRACE,
"mckk_intr - aborted transfer interrupt reason\n"
);
return IRQ_HANDLED;
// goto waiting_mode;
case init_trans_mode_end_intr_reason :
ME90_LOG(state, ME90_DL_TRACE,
"mckk_intr - end of init transfer modes interrupt reason\n"
);
mutex_enter(&state->mutex); /* start MUTEX */
state -> trans_mode_inited = 1;
if (interrupt_args.init_trans_results.mp_error_code != 0)
{
state -> trans_mode_init_error = EIO;
ME90_LOG(state, ME90_DL_ERROR,
"mckk_intr - init transfer modes finished with error"
" detected by MP driver 0x%02x\n",
interrupt_args.init_trans_results.mp_error_code
);
}
cv_broadcast(&state -> channel_cv);
mutex_exit(&state->mutex); /* end MUTEX */
return IRQ_HANDLED;
// goto waiting_mode;
case cnct_polling_good_intr_reason :
case cnct_polling_bad_intr_reason :
ME90_LOG(state, ME90_DL_TRACE,
"mckk_intr connection polling %s interrupt at time %s\n",
(intr_reason == cnct_polling_good_intr_reason) ? "good"
: "bad"
);
mckk_connection_polling_intr(state,
intr_reason == cnct_polling_bad_intr_reason,
intr_receiving_time
);
return IRQ_HANDLED;
// goto waiting_mode;
case undefined_intr_reason :
default:
ME90_LOG(state, ME90_DL_ERROR, /*!!!!!!!!!*/
"mckk_intr - undefined interrupt reason # %d\n",
intr_reason
);
return IRQ_HANDLED;
// goto waiting_mode;
}
}
irqreturn_t
mckk_interrupt(int irq, void* arg)
{
mcb_state_t * state = (mcb_state_t *)arg;
mc_wr_reg_t intr_reset_value;
// mutex_enter(&state->mutex); /* start MUTEX */
ME90_LOG(state, ME90_DL_TRACE, "mckk_interrupt !!!! \n");
ME90_LOG(state, ME90_DL_TRACE, "mckk_interrupt: irq = %d, TISB_read = 0x%x\n",
irq, state -> MC_CNTR_ST_REGS -> MC_RGEN_read.TI.TISB_read);
if (state -> MC_CNTR_ST_REGS -> MC_RGEN_read.TI.TISB_read) {
state->read_value.RGEN_read = state -> MC_CNTR_ST_REGS -> MC_TI_read; /* reading ints */
// state->waking_up_mckk_intr_handler = 1;
/* clear ints */
intr_reset_value.RGEN_write = 0;
state -> MC_CNTR_ST_REGS -> MC_TISB_write = intr_reset_value.RGEN_write;
// wake_up(&state->state_mckk_intr_handler);
// mutex_exit(&state->mutex);
// schedule_work(&state->interrupt_tqueue);
return IRQ_WAKE_THREAD;
}else{
// mutex_exit(&state->mutex);
return IRQ_NONE;
}
// mutex_exit(&state->mutex);
}
/*
* Free transfer buffers
*/
/*ARGSUSED*/
void
mckk_free_trans_bufs(
mcb_state_t *state,
me90drv_trbuf_desc_t *trans_buf_desc)
{
ME90_LOG(state, ME90_DL_TRACE,
"mckk_free_trans_bufs started for buffer 0x%lx\n",
trans_buf_desc);
mckk_dma_free_coherent(state, trans_buf_desc->dma.real_size,
trans_buf_desc->dma.dma, trans_buf_desc->dma.prim_dev_mem);
trans_buf_desc -> buf_address = NULL;
ME90_LOG(state, ME90_DL_TRACE,
"mckk_free_trans_bufs succeeded\n");
}
/*
* Delete I/O operation transfer buffer header structure
*/
/*ARGSUSED*/
void
mcb_delete_trans_header(
mcb_state_t *state,
trans_buf_t *trans_buf_p)
{
ME90_LOG(state, ME90_DL_TRACE,
"mckk_delete_trans_header started for buffer 0x%lx\n",
trans_buf_p);
if (!trans_buf_p -> trans_buf_desc.only_link)
mckk_free_trans_bufs(state, &trans_buf_p -> trans_buf_desc);
kmem_free(trans_buf_p, sizeof(trans_buf_t));
ME90_LOG(state, ME90_DL_TRACE,
"mckk_delete_trans_header succeeded\n");
}
/*
* Set the transfer buffer header results field to the initial state
*/
/*ARGSUSED*/
void
mckk_fill_trans_bufs(
mcb_state_t *state,
me90drv_trbuf_desc_t *trans_buf_desc)
{
ME90_LOG(NULL, ME90_DL_TRACE,
"mckk_fill_trans_bufs started for buffer 0x%lx\n",
trans_buf_desc);
if (
#ifdef __BLOCK_BUFFER_USE__
trans_buf_desc -> drv_buf_used &&
#endif /* __BLOCK_BUFFER_USE__ */
(state -> drv_general_modes & FILL_BUF_SPACE_DRV_MODE)) {
int cur_word = 0;
for (cur_word = 0;
cur_word < trans_buf_desc -> buf_size / sizeof (long);
cur_word ++) {
((long *) (trans_buf_desc -> buf_address))[cur_word] =
(long) &(((long *) (trans_buf_desc -> dma.prim_buf_addr))[cur_word]);
}
}
ME90_LOG(NULL, ME90_DL_TRACE,
"mckk_fill_trans_bufs succeeded for buffer 0x%lx\n",
trans_buf_desc);
}
/*
* Set the transfer buffer header results field to the initial state
*/
/*ARGSUSED*/
static void
mckk_init_trans_header(
mcb_state_t *state,
trans_buf_t *trans_buf_p)
{
ME90_LOG(state, ME90_DL_TRACE,
"mckk_init_trans_header started for buffer 0x%lx\n",
trans_buf_p);
trans_buf_p -> real_trans_size = 0;
trans_buf_p -> buf_offset = 0;
trans_buf_p -> gen_reg_state.RGEN_read = 0;
trans_buf_p -> mp_error_code = 0;
trans_buf_p -> sparc_error_code = 0;
trans_buf_p -> board_state_byte = 0;
trans_buf_p -> sp_state_byte = 0;
trans_buf_p -> trans_error = 0;
trans_buf_p -> trans_num = -1;
trans_buf_p -> intr_transfer_end = -1;
mckk_fill_trans_bufs(state, &trans_buf_p -> trans_buf_desc);
ME90_LOG(state, ME90_DL_TRACE,
"mckk_init_trans_header succeeded for buffer 0x%lx\n",
trans_buf_p);
}
/*
* Create driver private buffer header structure
*/
/*ARGSUSED*/
static int mckk_create_drv_buf(
mcb_state_t * state,
uio_t * uio_p,
int op_flags,
trans_spec_t * transfer_spec,
mcb_drv_buf_t ** new_trans_drv_buf_p
)
{
mcb_drv_buf_t * new_trans_drv_buf = NULL;
ME90_LOG(state, ME90_DL_TRACE,
"mckk_create_drv_buf started with uio_p 0x%lx\n",
uio_p
);
new_trans_drv_buf = kmem_alloc(sizeof(mcb_drv_buf_t),KM_NOSLEEP);
if (new_trans_drv_buf == NULL)
{
ME90_LOG(state, ME90_DL_ERROR,
"mckk_create_drv_buf cannot allocate kernel memory"
);
return EINVAL;
}
new_trans_drv_buf -> next_drv_buf = NULL;
new_trans_drv_buf -> uio_p = uio_p;
new_trans_drv_buf -> op_flags = op_flags;
new_trans_drv_buf -> trans_error = 0;
new_trans_drv_buf -> trans_completed = 0;
new_trans_drv_buf -> transfer_spec = transfer_spec;
cv_init(&new_trans_drv_buf -> trans_finish_cv);
*new_trans_drv_buf_p = new_trans_drv_buf;
ME90_LOG(state, ME90_DL_TRACE,
"mckk_create_drv_buf successed for uio_p 0x%lx\n",
uio_p
);
return 0;
}
/*
* Delete driver private buffer header structure
*/
/*ARGSUSED*/
static void mckk_delete_drv_buf(
mcb_state_t * state,
mcb_drv_buf_t * trans_drv_buf_p
)
{
ME90_LOG(state, ME90_DL_TRACE,
"mckk_delete_drv_buf started for buffer 0x%lx\n",
trans_drv_buf_p
);
cv_destroy(&trans_drv_buf_p -> trans_finish_cv);
kmem_free(trans_drv_buf_p,sizeof(mcb_drv_buf_t));
ME90_LOG(state, ME90_DL_TRACE,"mckk_delete_drv_buf successed\n");
}
/*
* Abort the DMA data hanguped transfer
*/
/*ARGSUSED*/
static int
abort_dma_transfer(
mcb_state_t *state,
int channel)
{
me90drv_chnl_state_t * channel_state = &state -> all_channels_state[channel];
int rval = 0;
mp_drv_args_t transfer_args;
ME90_LOG(state, ME90_DL_TRACE,"abort_dma_transfer started for channel %d\n",
channel
);
transfer_args.transfer.dev_num = channel;
transfer_args.transfer.opcode = 0;
transfer_args.transfer.mode = 0;
transfer_args.transfer.burst_size = 0;
transfer_args.transfer.address = 0;
transfer_args.transfer.size = 0;
transfer_args.transfer.repeation_num = 0;
if (channel_state -> streaming)
rval =
submit_mp_task(state,data_transfer_mp_task,&transfer_args,0,
NULL,
NULL,
0
);
else
rval =
submit_mp_task(state,transfer_abort_mp_task,&transfer_args,0,
NULL,
NULL,
0
);
if (rval == EMPRESTART)
{
ME90_LOG(state, ME90_DL_TRACE,
"abort_dma_transfer retrieve transfers for channel %d\n",
channel
);
rval = 0;
}
else if (rval != 0)
{
ME90_LOG(state, ME90_DL_ERROR,
"abort_dma_transfer failed for channel %d\n",
channel
);
}
else
{
ME90_LOG(state, ME90_DL_TRACE,
"abort_dma_transfer successed for channel %d\n",
channel
);
}
return rval;
}
/*
* Retrieve streaming channel after errors detected by MP driver in the
* adapter of the board.
*/
/*
* The driver attachment state
*/
static int mckk_init_minor_created = 0;
/*
* Driver chpoll entry point
*/
/*ARGSUSED*/
unsigned int mckk_chpoll(struct file *file, struct poll_table_struct *wait)
{
ME90_LOG(NULL, ME90_DL_TRACE,"mckk_chpoll called, but not implemented\n");
return ENXIO;
}
/*
* mckk_open
* Called for each open(2) call on the device.
*/
/*ARGSUSED*/
int mckk_open(struct inode *inode, struct file *file)
{
mcb_state_t *state;
dev_t dev = MKDEV(mckk_major, iminor(inode));
int instance;
int channel;
struct mckk_file_private* pdata;
ME90_LOG(NULL, ME90_DL_TRACE,"mckk_open started\n");
instance = MCB_INST(dev);
channel = MCB_CHAN(dev);
state = mckk_states[instance];
if ( state == NULL ) {
printk("~%s~_open: unattached instance %d\n", mod_name, instance);
return ENXIO;
}
mutex_enter(&state->mutex);
if ( state->opened ) {
me90drv_log_msg_num = 0;
pdata = ddi_malloc(sizeof (*pdata));
pdata->instance = instance;
pdata->dev = dev;
file->private_data = pdata;
state->open_channel_map |= CHNL_NUM_TO_MASK(channel);
state->opened = 1;
} else {
pdata = file->private_data;
if (pdata == NULL) {
printk("%s: file->private_data == NULL\n", __FUNCTION__);
mutex_exit(&state->mutex);
return -ENXIO;
}
}
pdata->count++;
mutex_exit(&state->mutex);
ME90_LOG(NULL, ME90_DL_TRACE,
"mckk_open succesed, instance %d channel %d\n",
instance, channel);
return 0;
}
/*
* Output results of the last transfer
*/
/*ARGSUSED*/
void
me90_output_trans_state(
mcb_state_t *state,
me90drv_trans_buf_t *trans_buf)
{
int buf_words = 0;
int cur_word = 0;
u_int *word_buf = NULL;
ME90_LOG(state, ME90_DL_TRACE,
"mckk_output_trans_state started for trans header 0x%08x\n",
trans_buf);
me90_log(state,0," transfer arguments and results\n");
#ifdef __BLOCK_BUFFER_USE__
if (trans_buf -> trans_buf_desc.drv_buf_used)
#endif /* __BLOCK_BUFFER_USE__ */
me90_log(state,0,
"transfer used driver buf: address 0x%08x buf size "
"0x%x transsize 0x%x real size 0x%x\n",
trans_buf -> trans_buf_desc.buf_address,
trans_buf -> trans_buf_desc.buf_size,
trans_buf -> trans_size,
trans_buf -> real_trans_size);
#ifdef __BLOCK_BUFFER_USE__
else
me90_log(state,0,
"transfer used system buf structure: trans "
"size 0x%x real size 0x%x\n",
trans_buf -> trans_size,
trans_buf -> real_trans_size);
#endif /* __BLOCK_BUFFER_USE__ */
me90_log(state ,0, "DMA virtual address 0x%08x size 0x%x\n",
/* trans_buf -> trans_buf_desc.cookie.dmac_address,
trans_buf -> trans_buf_desc.cookie.dmac_size*/
trans_buf -> trans_buf_desc.dma.prim_dev_mem,
trans_buf -> trans_buf_desc.dma.real_size);
#ifdef __BLOCK_BUFFER_USE__
if (trans_buf -> trans_buf_desc.drv_buf_used) {
#endif /* __BLOCK_BUFFER_USE__ */
buf_words = (trans_buf -> trans_buf_desc.buf_size +
(sizeof(u_int) - 1)) / sizeof(u_int);
word_buf = (u_int *) trans_buf -> trans_buf_desc.buf_address;
#ifdef __BLOCK_BUFFER_USE__
} else {
buf_words = (trans_buf -> trans_size +
(sizeof(u_int) - 1)) / sizeof(u_int);
/*word_buf = (u_int *) trans_buf -> trans_buf_desc.bp ->
b_un.b_addr;*/
word_buf = (u_int *) trans_buf -> trans_buf_desc.uio_p->uio_iov->iov_base;
}
#endif /* __BLOCK_BUFFER_USE__ */
me90_log(state,0,"transfer buffer contents:\n");
for (cur_word = 0; cur_word < buf_words; cur_word ++) {
me90_log(state, 0, "0x%08x 0x%08x : 0x%08x\n",
cur_word * sizeof(u_int), cur_word,
word_buf[cur_word]);
}
ME90_LOG(state, ME90_DL_TRACE,
"mckk_output_trans_state successed for trans header 0x%08x\n",
trans_buf);
}
/*
* Copy data from a MP base memory to a source kernel address. Source addresss
* and base memory address must have the same alignment into word
*/
/*ARGSUSED*/
int mckk_read_base_memory(
mcb_state_t *state,
caddr_t address_from,
caddr_t address_to,
size_t byte_size,
int char_data)
{
ME90_LOG(state, ME90_DL_TRACE,"mckk_read_base_memory unimplemented now\n");
return EINVAL;
}
/*
* Data transfer operations from/to base memory of MP and
* general memory of SPARC (mutex_enter must be done by caller)
*/
/*ARGSUSED*/
int me90_bmem_data_transfer(
mcb_state_t *state,
bmem_trans_desk_t *transfer_desk,
int write_op,
int mode,
int char_data,
caddr_t kmem_buf,
caddr_t *kmem_area_p
)
{
caddr_t kmem_area = NULL;
int rval = 0;
int kmem_size = 0;
int word_rem = 0;
if (write_op)
{
ME90_LOG(state, ME90_DL_TRACE,
"mckk_bmem_data_transfer from SPARC memory 0x%08x"
" to MP memory 0x%08x size 0x%x bytes\n",
transfer_desk -> mem_address,
transfer_desk -> mp_bmem_address,
transfer_desk -> byte_size
);
}
else
{
ME90_LOG(state, ME90_DL_TRACE,
"mckk_bmem_data_transfer from MP memory 0x%08x"
" to SPARC memory 0x%08x size 0x%x bytes\n",
transfer_desk -> mp_bmem_address,
transfer_desk -> mem_address,
transfer_desk -> byte_size
);
}
if ((long) transfer_desk -> mp_bmem_address < 0 ||
(long) transfer_desk -> mp_bmem_address >= MC_BMEM_REG_SET_LEN ||
(long) transfer_desk -> mp_bmem_address + transfer_desk -> byte_size >
MC_BMEM_REG_SET_LEN
)
{
ME90_LOG(state, ME90_DL_ERROR,
"mckk_bmem_data_transfer bad MP BMEM address 0x%08x and/or"
" size 0x%x\n",
transfer_desk -> mp_bmem_address,
transfer_desk -> byte_size
);
return EINVAL;
}
word_rem = ((long) transfer_desk -> mp_bmem_address & (sizeof(u_int)-1));
kmem_size = transfer_desk -> byte_size + word_rem;
if (kmem_buf == NULL)
kmem_area = (caddr_t) kmem_alloc(kmem_size,KM_NOSLEEP);
else
kmem_area = kmem_buf;
if (kmem_area == NULL)
{
ME90_LOG(state, ME90_DL_ERROR,
"mckk_bmem_data_transfer: kmem_alloc no memory is available\n"
);
return EINVAL;
}
if (write_op)
{
if (ddi_copyin(transfer_desk -> mem_address,
&kmem_area[word_rem],
transfer_desk -> byte_size /*,
mode*/
)
)
{
if (kmem_buf == NULL)
kmem_free(kmem_area,kmem_size);
ME90_LOG(state, ME90_DL_ERROR,
"mckk_bmem_data_transfer ddi_copyin failed\n");
return (EFAULT);
}
}
if (write_op)
rval = mckk_write_base_memory(state,
&kmem_area[word_rem],
transfer_desk -> mp_bmem_address,
transfer_desk -> byte_size,
char_data
);
else
rval = mckk_read_base_memory(state,
&kmem_area[word_rem],
transfer_desk -> mp_bmem_address,
transfer_desk -> byte_size,
char_data
);
if (rval != 0)
{
if (kmem_buf == NULL)
kmem_free(kmem_area,kmem_size);
ME90_LOG(state, ME90_DL_ERROR,
"mckk_bmem_data_transfer read/write base memory failed\n"
);
return rval;
}
if (!write_op)
{
if (ddi_copyout(&kmem_area[word_rem],
transfer_desk -> mem_address,
transfer_desk -> byte_size /*,
mode*/
)
)
{
if (kmem_buf == NULL)
kmem_free(kmem_area,kmem_size);
ME90_LOG(state, ME90_DL_ERROR,
"mckk_bmem_data_transfer ddi_copyout failed\n");
return (EFAULT);
}
}
if (kmem_buf == NULL)
kmem_free(kmem_area,kmem_size);
else if (kmem_area_p != NULL)
*kmem_area_p = &kmem_area[word_rem];
ME90_LOG(state, ME90_DL_TRACE,
"mckk_bmem_data_transfer succeeded\n"
);
return 0;
}
/*
* Startup MP (driver ur any other code)
*/
/*ARGSUSED*/
int me90_startup_mp(
mcb_state_t *state,
int cmd,
int mode)
{
caddr_t mp_init_code_p = NULL;
mp_drv_args_t *mp_drv_init_info_p = NULL;
sparc_drv_args_t drv_load_results;
me90_mp_rom_drv_t *mp_rom_drv_init_area = NULL;
u_int rom_drv_init_code[] =
ME90_MP_ROM_DRV_INIT_CODE;
int rval = 0;
#ifdef DEBUG
printk("mckk_startup_mp started with command 0x%x\n", cmd);
#endif
mutex_enter(&state->mutex); /* start MUTEX */
state->mp_init_code.mp_bmem_address =
(caddr_t) MC_MP_INIT_AREA_BMEM_ADDR;
if (me90_reset_mp(state, 2, cmd == ME90IO_STARTUP_MP_ROM_DRV) != 0) {
#ifdef DEBUG
printk( "mckk_startup_mp: MP reset and halt finished with errors\n");
#endif
}
if (cmd == ME90IO_STARTUP_MP_ROM_DRV) {
rval = mckk_write_base_memory(state,
(caddr_t)&rom_drv_init_code,
state -> mp_init_code.mp_bmem_address,
sizeof(rom_drv_init_code), 1);
if (rval != 0) {
printk( "mckk_startup_mp - write ROM driver "
"init code in bmem failed\n");
}
} else {
if (!state -> mp_drv_loaded) {
mutex_exit(&state->mutex); /* end MUTEX */
printk( "mckk_startup_mp MP driver code did not loaded"
" in the BMEM\n");
return (EINVAL);
}
rval = me90_bmem_data_transfer(state,
&state -> mp_init_code, 1, mode,1,
state -> mp_init_area_copy, &mp_init_code_p);
if (rval != 0) {
mutex_exit(&state->mutex); /* end MUTEX */
printk("mckk_startup_mp MP startup failed\n");
return rval;
}
}
if (state -> mp_init_code.mp_drv_init_info != NULL &&
state -> mp_init_code.mp_drv_init_info_size > 0) {
if (cmd == ME90IO_STARTUP_MP_CODE) {
bmem_trans_desk_t mp_code_init_info;
mp_code_init_info.mem_address =
state -> mp_init_code.mp_drv_init_info;
mp_code_init_info.mp_bmem_address =
state -> mp_init_code.mp_drv_init_info_addr;
mp_code_init_info.byte_size =
state -> mp_init_code.mp_drv_init_info_size;
rval = me90_bmem_data_transfer(state, &mp_code_init_info,
1, mode, 0, NULL, NULL);
if (rval != 0) {
mutex_exit(&state->mutex); /* end MUTEX */
printk( "mckk_startup_mp MP init info "
"load failed\n");
return rval;
}
} else {
if (state -> mp_init_code.mp_drv_init_info_size >
sizeof (mp_drv_args_t)) {
mutex_exit(&state->mutex); /* end MUTEX */
printk( "mckk_startup_mp too long MP "
"init info 0x%lx > 0x%lx\n",
(u_long)state -> mp_init_code.
mp_drv_init_info_size,
(u_long)sizeof (mp_drv_args_t));
return (EINVAL);
}
mp_drv_init_info_p = &state -> mp_drv_init_info;
if (copy_from_user ((void *)state -> mp_drv_init_info.args_area,
state -> mp_init_code.mp_drv_init_info,
state -> mp_init_code.mp_drv_init_info_size) != 0) {
printk( "mckk_startup_mp ddi_copyin "
"failed for MP init info\n");
return (EFAULT);
}
}
}
state -> mp_init_code.mem_address = mp_init_code_p;
if ( cmd == ME90IO_STARTUP_MP_ROM_DRV )
state -> mp_debug_drv_flag = 0;
else
state -> mp_debug_drv_flag = 1;
if ( cmd == ME90IO_STARTUP_MP_CODE ) {
rval = me90drv_reset_general_regs(state, 0);
state -> mp_drv_started = 1;
state -> mp_state = started_mp_state;
mutex_exit(&state->mutex); /* end MUTEX */
if ( rval != 0 ) {
printk( "mckk_startup_mp MP code startup "
"finished with error\n");
} else {;
#ifdef DEBUG
printk( "mckk_startup_mp MP code stratup "
"succeeded\n");
#endif
}
return rval;
}
mp_rom_drv_init_area = (me90_mp_rom_drv_t *)
&state -> ME90DRV_BMEM[ME90_MP_ROM_DRV_INIT_ADDR];
mp_rom_drv_init_area -> debug_drv_start =
(cmd != ME90IO_STARTUP_MP_ROM_DRV);
mp_rom_drv_init_area -> rom_disable = 0;
rval = me90drv_submit_mp_task(state, drv_load_mp_task,
mp_drv_init_info_p, 1, NULL, &drv_load_results, 0);
if ( rval != 0 ) {
if (cmd == ME90IO_STARTUP_MP_ROM_DRV)
state -> mp_rom_drv_enable = 0;
mutex_exit(&state->mutex); /* end MUTEX */
#ifdef DEBUG
printk("mckk_startup_mp MP driver init failed\n");
#endif
return rval;
}
state -> mp_drv_started = 1;
if ( cmd == ME90IO_STARTUP_MP_ROM_DRV )
state -> mp_rom_drv_enable =
!mp_rom_drv_init_area -> rom_disable;
mutex_exit(&state->mutex); /* end MUTEX */
#ifdef DEBUG
printk("mckk_startup_mp MP driver init succeeded\n");
#endif
return 0;
}
int rmv_dev(int inst, me90drv_chnl_state_t * chd, uchar_t channel)
{
char name[64];
int error = 0;
#ifdef MCKK_DBG
int minor = MCB_MINOR(inst, channel);
#endif /* MBKP_DBG */
(void)sprintf(name, "%s_%d_:%d", mod_name, inst, channel);
error = ddi_unlink(MCKK_DIR, name);
if ( error ) {
printk("rmv_dev: mcst_unlink failed, error = %d\n", error);
return error;
}
#ifdef MCKK_DBG
printk("%s%d_detach.rmv_dev: minor = %u !~~!\n",
board_name, channel, minor);
#endif /* MBKP_DBG */
return error;
}
#include "mckk_ioctl.h"
/// HERE IS THE END OF GENERAL DRIVER BODY
/*
* Driver attach (init) entry point
*/
static int mckk_sbus_probe(struct of_device *op, const struct of_device_id *match)
{
int minor;
int instance;
mcb_state_t *state;
int rval;
char name[64];
int regs_mapped = 0;
int attach_flags = 0;
int add_attach_flags = 0;
int cur_chnl = 0;
int n_regs;
int i;
void *regs;
#if MCKK_INTERRUPT_DEBUG
unsigned long bit;
int irq;
#endif /* MCKK_INTERRUPT_DEBUG */
u_int max_reg_groups_number = 0;
u_int min_reg_groups_number = 0;
int without_eprom = 0;
for ( instance = 0; instance < MAX_MCKK_INSTANCES; instance++ ) {
if ( mckk_states[instance] == NULL ) {
break;
}
}
if ( instance >= MAX_MCKK_INSTANCES ) {
printk("Too many mvps in system (max = %d)\n", MAX_MCKK_INSTANCES);
return -EINVAL;
}
mckk_major = register_chrdev(0, MCKK_NAME, &mckk_fops);
state = ddi_malloc(sizeof (*state));
if ( state == NULL ) {
return -EFAULT;
}
attach_flags |= SOFT_STATE_ALLOCATED;
/*
* Initialize the soft state for this instance
*/
state->op = op;
state->inst = instance;
state->major = mckk_major;
state->opened = 0;
state->open_flags = 0;
state->open_channel_map = 0;
state->drv_comm_busy = 0;
state->drv_general_modes = DEFAULT_GENERAL_DRV_MODE;
state->intr_number = 0;
state->intr_seted = 0;
state->mp_drv_loaded = 0;
state->mp_state = undef_mp_state;
state->mp_drv_started = 0;
state->mp_rom_drv_enable = 0;
state->mp_debug_drv_flag = 0;
state->set_tlrm = 1;
state->mp_init_code.mem_address = NULL;
state->mp_init_code.mp_bmem_address = NULL;
state->mp_init_code.byte_size = 0;
state->mp_init_code.mp_drv_init_info = NULL;
state->mp_init_code.mp_drv_init_info_size = 0;
state->timeouts_num = 0;
state->timeout_idnt.expires = 0;
state->timeout_type = no_timeout_type;
state->timeout_rem = 0;
state->type_unit = UNDEF_UT;
dev_set_drvdata(&op->dev, state);
for ( cur_chnl = 0; cur_chnl < MAX_ME90DRV_BOARD_CHANNEL_NUM; cur_chnl++ ) {
me90drv_chnl_state_t *mckk_channel = NULL;
mckk_channel = &state -> all_channels_state[cur_chnl];
mckk_channel -> busy = 0;
mckk_channel -> in_progress = 0;
mckk_channel -> transfer_state = no_trans_state;
mckk_channel -> timeout_type = no_timeout_type;
mckk_channel -> timeout_rem = 0;
mckk_channel -> wait_list_start = NULL;
mckk_channel -> wait_list_end = NULL;
mckk_channel -> wait_list_size = 0;
mckk_channel -> in_progress_start = NULL;
mckk_channel -> in_progress_end = NULL;
mckk_channel -> in_progress_size = 0;
mckk_channel -> completed_trans_start = NULL;
mckk_channel -> completed_trans_end = NULL;
mckk_channel -> completed_trans_size = 0;
mckk_channel -> ready_atrans_start = NULL;
mckk_channel -> ready_atrans_end = NULL;
mckk_channel -> ready_atrans_size = 0;
mckk_channel -> async_trans_num = 0;
mckk_channel -> term_trans_processed = 0;
mckk_channel -> last_term_trans_buf = NULL;
mckk_channel -> trans_num = 0;
}
me90drv_init_drv_state(state);
state->type_unit = MCKK_UT;
/*
* SBUS and MP clock-frequency definition
*/
me90_sbus_clock_freq = mckk_clock_freq(state);
dbgmckk("%s(): me90_sbus_clock_freq = %d\n", __func__, me90_sbus_clock_freq);
if ( me90_sbus_clock_freq < 10 * 1000000 ||
me90_sbus_clock_freq > 25 * 1000000 ) {
printk("%s() : SBus clock frequency %d out "
"of range\n", __func__, me90_sbus_clock_freq / 1000000);
goto m_err;
}
me90_sbus_nsec_cycle = 1000 * 1000000 / me90_sbus_clock_freq; /* nsec */
me90_mp_clock_freq = me90_sbus_clock_freq / 2;
me90_mp_nsec_cycle = 1000 * 1000000 / me90_mp_clock_freq; /* nsec */
/*
* Map in operating registers
*/
me90drv_init_reg_sets_pointers(state, state->type_unit);
n_regs = mckk_nregs(state);
max_reg_groups_number = me90drv_get_reg_sets_number(state->type_unit, 1);
min_reg_groups_number = me90drv_get_reg_sets_number(state->type_unit, 0);
if ( n_regs == max_reg_groups_number )
without_eprom = 0;
else if ( n_regs == min_reg_groups_number )
without_eprom = 1;
else {
ME90_LOG(state, ME90_DL_ERROR,
"%s(): wrong number of register "
"sets %d instead %d or %d\n", __func__,
n_regs,min_reg_groups_number,max_reg_groups_number);
attach_flags |= ERRORS_SIGN;
return -EFAULT;
}
for ( i = 0; i < n_regs; i++ ) {
regs = mckk_ioremap(state, i);
if ( !me90drv_put_reg_set_pointer(state,
i + without_eprom, (caddr_t)regs) ) {
ME90_LOG(state, ME90_DL_ERROR,
"%s(): "
"put_reg_set_pointer failed for "
"register set # %d\n", __func__, i);
attach_flags |= ERRORS_SIGN;
return -EFAULT;
} else {
ME90_LOG(state, ME90_DL_TRACE,
"%s(): map regs set # "
"%d, virt_addr = 0x%lx\n", __func__, i,
regs);
}
}
#if 0
/* SHOULD BE REMOVED*/
ME90_LOG(state, ME90_DL_TRACE,"Read GEN REGS: address %lx value %08x\n",
&state -> MC_CNTR_ST_REGS-> MC_TI_read,
state -> MC_CNTR_ST_REGS-> MC_TI_read
);
#endif
ME90_LOG(state, ME90_DL_TRACE,
"%s(): map reg MC_EPROM_REG_SET_LEN = 0x%lx\n", __func__,
MC_EPROM_REG_SET_LEN);
ME90_LOG(state, ME90_DL_TRACE,
"%s(): map reg MC_CNTR_ST_REG_SET_LEN = 0x%lx\n", __func__,
MC_CNTR_ST_REG_SET_LEN);
ME90_LOG(state, ME90_DL_TRACE,
"%s(): map reg MC_BMEM_REG_SET_LEN = 0x%lx\n", __func__,
MC_BMEM_REG_SET_LEN);
attach_flags |= REGS_MAPPED;
regs_mapped = 1;
/*
* Initialize the module condition variables for the instance
*/
cv_init(&state->channel_cv);
cv_init(&state->trans_start_cv);
cv_init(&state->atrans_end_cv);
cv_init(&state->drv_comm_cv);
// state -> system_burst = 0x20;
state->system_burst = MCB_ENABLE_BURST_SIZES;
attach_flags |= CHANNEL_CV_ADDED;
if ( me90_reset_mp(state, 2, 1) != 0 ) {
printk("mckk attach: Reset board and MP finished with error\n");
return -EFAULT;
}
/*
* Initialize the mutex for this instance
*/
mutex_init(&state->mutex);
raw_spin_lock_init(&state->lock);
attach_flags |= MUTEX_ADDED;
/* interrupt handler and watchdog threads are defined here */
#if 0
state->waking_up_mckk_intr_handler = 0;
state->state_mckk_intr_handler_shutdown = 0;
state->waking_up_mckk_watchdog_handler = 0;
state->mckk_watchdog_handler_shutdown = 0;
init_waitqueue_head(&(state->state_mckk_intr_handler));
state->pid_state_mckk_intr_handler = kernel_thread(state_mckk_intr_handler, dip, 0);
init_waitqueue_head(&(state->mckk_watchdog_handler));
state->pid_mckk_watchdog_handler = kernel_thread(mckk_watchdog_handler, state, 0);
#endif
// INIT_WORK(&(state->interrupt_tqueue), state_mckk_intr_handler, dip);
INIT_WORK(&(state->watchdog_tqueue), mckk_watchdog_handler);
/* end of interrupt handler and watchdog routines */
rval = mckk_request_irq(state);
if ( rval ) {
printk("request_irq fail\n");
goto m_err;
}
attach_flags |= INTERRUPT_ADDED;
state->intr_seted++;
#if MCKK_INTERRUPT_DEBUG
printk("%s(): irq = %d\n", __func__, op->irqs[0]);
printk("%s(): int_mask = 0x%x\n", __func__, mcst_read(INTERRUPT_REG_BASE + INTERRUPT_MASK_REG));
#endif /* MCKK_INTERRUPT_DEBUG */
/*
* Specific for module types driver additional Attachments
*/
if ( me90drv_attach_add(state, &add_attach_flags) != 0 )
goto m_err;
/*
* Startup MP driver from ROM
*/
if (me90_startup_mp(state, ME90IO_STARTUP_MP_ROM_DRV, /*FKIOCTL*/ 0) != 0) {
printk("%s(): cannot startup MP ROM driver\n", __func__);
}
/*
* Create minor nodes for this instance
*/
for ( cur_chnl = mckk_init_minor_created; cur_chnl < MAX_ME90DRV_BOARD_CHANNEL_NUM; cur_chnl++ ) {
minor = MCB_MINOR(instance, cur_chnl);
(void) sprintf(name, "%s_%d_:%d", mod_name, instance,
cur_chnl);
dbgmckkdetail("%s(): getting minor for %d\n", __func__, minor);
if ( ddi_create_minor(MCKK_DIR, name, S_IFCHR, new_encode_dev(MKDEV(mckk_major, minor))) ) {
printk("mvp: mcst_create_minor failed %d\n", rval);
goto m_err;
}
attach_flags |= MINOR_NODE_CREATED;
}
dbgmckk("%s() is finished for inst %d\n", __func__,
instance);
return 0;
m_err:
if ( (attach_flags & INTERRUPT_ADDED) ) {
if (state->intr_seted > 0){
mckk_free_irq(state);
state -> intr_seted = 0;
}
}
if ( add_attach_flags != 0 )
me90drv_detach_add(state, add_attach_flags, 1);
if ( attach_flags & CHANNEL_CV_ADDED ) {
cv_destroy(&state -> channel_cv);
cv_destroy(&state -> trans_start_cv);
cv_destroy(&state -> atrans_end_cv);
cv_destroy(&state -> drv_comm_cv);
}
if ( attach_flags & MUTEX_ADDED ) {
// TODO: it was uncommented
//mutex_destroy(&state->mutex);
}
if ( attach_flags & REGS_MAPPED ) {
me90drv_unmap_reg_sets(state);
}
if ( attach_flags & MINOR_NODE_CREATED ) {
for ( cur_chnl = 0; cur_chnl < MAX_ME90DRV_BOARD_CHANNEL_NUM; cur_chnl++ )
rmv_dev(instance, NULL, cur_chnl);
}
kfree(state);
unregister_chrdev(mckk_major, MCKK_NAME);
printk("%s(): FAILED\n", __func__);
return DDI_FAILURE;
}
int
free_chan(mcb_state_t *state, me90drv_chnl_state_t *channel_state, int cur_chnl)
{
int instance;
/*
* If we have outstanding opens, we cannot detach
*/
if ( state->opened ) {
ME90_LOG(state, ME90_DL_ERROR,
"free_chan - device not opened\n");
return DDI_FAILURE;
}
instance = state->inst;
if ( channel_state->in_progress )
ME90_LOG(state, ME90_DL_ERROR,
"free_chan: detach channel %d with "
"transfer in progress\n", cur_chnl);
if ( channel_state->busy ||
channel_state->in_progress_start != NULL ||
channel_state->in_progress_end != NULL ||
channel_state->in_progress_size != 0 ||
channel_state->wait_list_start != NULL ||
channel_state->wait_list_end != NULL ||
channel_state->wait_list_size != 0 ) {
ME90_LOG(state, ME90_DL_ERROR,
"free_chan: detach busy or with transfers "
"channel %d\n", cur_chnl);
}
if ( channel_state->completed_trans_start != NULL ||
channel_state->completed_trans_end != NULL ||
channel_state->completed_trans_size != 0 ||
channel_state->term_trans_processed != 0 ) {
ME90_LOG(state, ME90_DL_ERROR,
"free_chan: detach channel %d with not "
"processed queue of completed transfers\n",
cur_chnl);
}
if ( channel_state->ready_atrans_start != NULL ||
channel_state->ready_atrans_end != NULL ||
channel_state->ready_atrans_size != 0 ||
channel_state->async_trans_num != 0 ) {
ME90_LOG(state, ME90_DL_ERROR,
"free_chan: detach channel %d with not "
"empty queue of ready asynchronous transfers\n",
cur_chnl);
mckk_release_all_async_trans(state, cur_chnl);
}
if ( channel_state->last_term_trans_buf != NULL )
ME90_LOG(state, ME90_DL_ERROR,
"free_chan: last transfer buf not freed "
"channel %d\n", cur_chnl);
/*
* Reset board and MP
*/
me90drv_reset_general_regs(state,2);
/*
* Remove interrupt handler in ddi_unrgstr_dev(dip)
*/
if ( state->intr_seted > 0 ) {
mckk_free_irq(state);
state->intr_seted = 0;
}
/*
* Remove timeout servises
*/
if ( state->timeouts_num > 0 ) {
ME90_LOG(state, ME90_DL_ERROR,
"free_chan: %d timeouts not handled\n",
state -> timeouts_num);
if ( state->timeout_idnt.expires != 0 )
/* untimeout(state -> timeout_idnt);*/
del_timer_sync(&state -> timeout_idnt);
} else if ( state->timeout_idnt.expires > 0 ) {
ME90_LOG(state, ME90_DL_ERROR,
"free_chan: not empty timeout identifier without"
" timeouts\n");
del_timer_sync(&state->timeout_idnt);
/* untimeout(state -> timeout_idnt);*/
}
/*
* Detach the per-instance conditional variables and mutex
*/
cv_destroy(&state->channel_cv);
cv_destroy(&state->trans_start_cv);
cv_destroy(&state->atrans_end_cv);
cv_destroy(&state->drv_comm_cv);
// TODO: it was uncommented
//mutex_destroy(&state->mutex);
/*
* Detach a module specific additional items
*/
me90drv_detach_add(state, 0, 1);
/*
* Unmap registers (from user here and from device in ddi_unrgstr_dev(dip))
* No nessesary to unmap from user;
*/
// me90drv_unmap_reg_sets(state);
return DDI_SUCCESS;
}
/**
* Detach()
* Free resources allocated in mckk_sbus_probe
*/
static int mckk_sbus_remove(struct of_device *op)
{
struct mckk_state *xsp = dev_get_drvdata(&op->dev);
int cur_chnl = 0;
int error = 0;
if ( xsp->opened ) {
ME90_LOG(xsp, ME90_DL_ERROR,
"mckk_detach cannot detach opened device\n");
return DDI_FAILURE;
}
#if 0
/* Killing interrupt handler and watchdog threads */
// kill_proc(xsp->pid_state_mckk_intr_handler, SIGKILL, 1);
xsp->state_mckk_intr_handler_shutdown = 1;
wake_up(&xsp->state_mckk_intr_handler);
while (xsp->state_mckk_intr_handler_shutdown != 0){
schedule_timeout(1);
}
// kill_proc(xsp->pid_mckk_watchdog_handler, SIGKILL, 1);
xsp->mckk_watchdog_handler_shutdown = 1;
wake_up(&xsp->mckk_watchdog_handler);
while (xsp->mckk_watchdog_handler_shutdown != 0){
schedule_timeout(1);
}
#endif
for ( cur_chnl = 0; cur_chnl < MAX_ME90DRV_BOARD_CHANNEL_NUM; cur_chnl++ ) {
error = free_chan(xsp, &xsp->all_channels_state[cur_chnl], cur_chnl);
if ( error == DDI_FAILURE )
return error;
error = (int)rmv_dev(xsp->inst, NULL, cur_chnl);
}
me90drv_unmap_reg_sets(xsp);
unregister_chrdev(xsp->major, MCKK_NAME);
mckk_states[xsp->inst] = NULL;
kfree(xsp);
dev_set_drvdata(&op->dev, NULL);
return 0;
}
static const struct of_device_id mckk_sbus_match[] = {
{
.name = board_name,
},
{},
};
MODULE_DEVICE_TABLE(of, mckk_sbus_match);
static struct of_platform_driver mckk_sbus_driver = {
.name = MCKK_NAME,
.match_table = mckk_sbus_match,
.probe = mckk_sbus_probe,
.remove = mckk_sbus_remove,
};
/// Check for hardware presence
static int
check_hardware(const char *name)
{
struct device_node *dp;
int inst = 0;
for_each_node_by_name(dp, name)
inst++;
if ( !inst )
return 0;
return inst;
}
/* Find all the lance cards on the system and initialize them */
static int __init mckk_init(void)
{
if ( check_hardware(MCKK_NAME) == 0 )
return -ENODEV;
return of_register_driver(&mckk_sbus_driver, &of_bus_type);
}
static void __exit mckk_exit(void)
{
of_unregister_driver(&mckk_sbus_driver);
}
module_init(mckk_init);
module_exit(mckk_exit);
MODULE_LICENSE("Copyright by MCST 2004");
MODULE_DESCRIPTION("MCKK driver");