* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/timer.h>
+#include <linux/mempool.h>
#include <asm/ccwdev.h>
#include <asm/io.h>
#include <asm/timex.h>
#include <asm/debug.h>
+#include <asm/s390_rdev.h>
#include <asm/qdio.h>
#include "cio.h"
/******************** HERE WE GO ***********************************/
static const char version[] = "QDIO base support version 2";
+extern struct bus_type ccw_bus_type;
-#ifdef QDIO_PERFORMANCE_STATS
+static int qdio_performance_stats = 0;
static int proc_perf_file_registration;
static unsigned long i_p_c, i_p_nc, o_p_c, o_p_nc, ii_p_c, ii_p_nc;
static struct qdio_perf_stats perf_stats;
-#endif /* QDIO_PERFORMANCE_STATS */
static int hydra_thinints;
static int is_passthrough = 0;
static __u32 * volatile indicators;
static __u32 volatile spare_indicator;
static atomic_t spare_indicator_usecount;
+#define QDIO_MEMPOOL_SCSSC_ELEMENTS 2
+static mempool_t *qdio_mempool_scssc;
static debug_info_t *qdio_dbf_setup;
static debug_info_t *qdio_dbf_sbal;
static inline __u64
qdio_get_micros(void)
{
- return (get_clock() >> 10); /* time>>12 is microseconds */
+ return (get_clock() >> 12); /* time>>12 is microseconds */
}
/*
QDIO_DBF_TEXT4(0,trace,"sigasync");
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.siga_syncs++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ perf_stats.siga_syncs++;
cc = do_siga_sync(q->schid, gpr2, gpr3);
if (cc)
__u32 busy_bit;
__u64 start_time=0;
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.siga_outs++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ perf_stats.siga_outs++;
QDIO_DBF_TEXT4(0,trace,"sigaout");
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
QDIO_DBF_TEXT4(0,trace,"sigain");
QDIO_DBF_HEX4(0,trace,&q,sizeof(void*));
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.siga_ins++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ perf_stats.siga_ins++;
cc = do_siga_input(q->schid, q->mask);
unsigned char state = 0;
struct qdio_irq *irq = (struct qdio_irq *) q->irq_ptr;
- if (!atomic_swap(&q->polling,0))
+ if (!atomic_xchg(&q->polling,0))
return 1;
QDIO_DBF_TEXT4(0,trace,"stoppoll");
if (unlikely(qdio_reserve_q(q))) {
qdio_release_q(q);
-#ifdef QDIO_PERFORMANCE_STATS
- o_p_c++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ o_p_c++;
/* as we're sissies, we'll check next time */
if (likely(!atomic_read(&q->is_in_shutdown))) {
qdio_mark_q(q);
}
return;
}
-#ifdef QDIO_PERFORMANCE_STATS
- o_p_nc++;
- perf_stats.tl_runs++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats) {
+ o_p_nc++;
+ perf_stats.tl_runs++;
+ }
/* see comment in qdio_kick_outbound_q */
siga_attempts=atomic_read(&q->busy_siga_counter);
if (q->is_iqdio_q) {
/*
- * for asynchronous queues, we better check, if the fill
- * level is too high. for synchronous queues, the fill
- * level will never be that high.
+ * for asynchronous queues, we better check, if the sent
+ * buffer is already switched from PRIMED to EMPTY.
*/
- if (atomic_read(&q->number_of_buffers_used)>
- IQDIO_FILL_LEVEL_TO_POLL)
+ if ((q->queue_type == QDIO_IQDIO_QFMT_ASYNCH) &&
+ !qdio_is_outbound_q_done(q))
qdio_mark_q(q);
} else if (!q->hydra_gives_outbound_pcis)
#ifdef QDIO_USE_PROCESSING_STATE
if (last_position>=0)
- set_slsb(q, &last_position, SLSB_P_INPUT_NOT_INIT, &count);
+ set_slsb(q, &last_position, SLSB_P_INPUT_PROCESSING, &count);
#endif /* QDIO_USE_PROCESSING_STATE */
QDIO_DBF_HEX4(0,trace,&q->first_to_check,sizeof(int));
{
int i;
-#ifdef QDIO_PERFORMANCE_STATS
static int old_pcis=0;
static int old_thinints=0;
- if ((old_pcis==perf_stats.pcis)&&(old_thinints==perf_stats.thinints))
- perf_stats.start_time_inbound=NOW;
- else
- old_pcis=perf_stats.pcis;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats) {
+ if ((old_pcis==perf_stats.pcis)&&
+ (old_thinints==perf_stats.thinints))
+ perf_stats.start_time_inbound=NOW;
+ else
+ old_pcis=perf_stats.pcis;
+ }
i=qdio_get_inbound_buffer_frontier(q);
if ( (i!=GET_SAVED_FRONTIER(q)) ||
q->siga_error=0;
q->error_status_flags=0;
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.inbound_time+=NOW-perf_stats.start_time_inbound;
- perf_stats.inbound_cnt++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats) {
+ perf_stats.inbound_time+=NOW-perf_stats.start_time_inbound;
+ perf_stats.inbound_cnt++;
+ }
}
static inline void
*/
if (unlikely(qdio_reserve_q(q))) {
qdio_release_q(q);
-#ifdef QDIO_PERFORMANCE_STATS
- ii_p_c++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ ii_p_c++;
/*
* as we might just be about to stop polling, we make
* sure that we check again at least once more
tiqdio_sched_tl();
return;
}
-#ifdef QDIO_PERFORMANCE_STATS
- ii_p_nc++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ ii_p_nc++;
if (unlikely(atomic_read(&q->is_in_shutdown))) {
qdio_unmark_q(q);
goto out;
irq_ptr = (struct qdio_irq*)q->irq_ptr;
for (i=0;i<irq_ptr->no_output_qs;i++) {
oq = irq_ptr->output_qs[i];
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.tl_runs--;
-#endif /* QDIO_PERFORMANCE_STATS */
- if (!qdio_is_outbound_q_done(oq))
+ if (!qdio_is_outbound_q_done(oq)) {
+ if (qdio_performance_stats)
+ perf_stats.tl_runs--;
__qdio_outbound_processing(oq);
+ }
}
}
if (unlikely(qdio_reserve_q(q))) {
qdio_release_q(q);
-#ifdef QDIO_PERFORMANCE_STATS
- i_p_c++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ i_p_c++;
/* as we're sissies, we'll check next time */
if (likely(!atomic_read(&q->is_in_shutdown))) {
qdio_mark_q(q);
}
return;
}
-#ifdef QDIO_PERFORMANCE_STATS
- i_p_nc++;
- perf_stats.tl_runs++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats) {
+ i_p_nc++;
+ perf_stats.tl_runs++;
+ }
again:
if (qdio_has_inbound_q_moved(q)) {
if (unlikely(qdio_reserve_q(q))) {
qdio_release_q(q);
-#ifdef QDIO_PERFORMANCE_STATS
- ii_p_c++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ ii_p_c++;
/*
* as we might just be about to stop polling, we make
* sure that we check again at least once more
{
QDIO_DBF_TEXT4(0,trace,"iqdio_tl");
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.tl_runs++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ perf_stats.tl_runs++;
tiqdio_inbound_checks();
}
}
kfree(irq_ptr->qdr);
- kfree(irq_ptr);
+ free_page((unsigned long) irq_ptr);
}
static void
int result=-ENOMEM;
for (i=0;i<no_input_qs;i++) {
- q=kmalloc(sizeof(struct qdio_q),GFP_KERNEL);
+ q = kzalloc(sizeof(struct qdio_q), GFP_KERNEL);
if (!q) {
QDIO_PRINT_ERR("kmalloc of q failed!\n");
goto out;
}
- memset(q,0,sizeof(struct qdio_q));
-
- q->slib=kmalloc(PAGE_SIZE,GFP_KERNEL);
+ q->slib = kmalloc(PAGE_SIZE, GFP_KERNEL);
if (!q->slib) {
QDIO_PRINT_ERR("kmalloc of slib failed!\n");
goto out;
}
for (i=0;i<no_output_qs;i++) {
- q=kmalloc(sizeof(struct qdio_q),GFP_KERNEL);
+ q = kzalloc(sizeof(struct qdio_q), GFP_KERNEL);
if (!q) {
goto out;
}
- memset(q,0,sizeof(struct qdio_q));
-
q->slib=kmalloc(PAGE_SIZE,GFP_KERNEL);
if (!q->slib) {
QDIO_PRINT_ERR("kmalloc of slib failed!\n");
void *ptr;
int available;
- sprintf(dbf_text,"qfqs%4x",cdev->private->sch_no);
+ sprintf(dbf_text,"qfqs%4x",cdev->private->schid.sch_no);
QDIO_DBF_TEXT0(0,setup,dbf_text);
for (i=0;i<no_input_qs;i++) {
q=irq_ptr->input_qs[i];
q->sbal[j]=*(outbound_sbals_array++);
q->queue_type=q_format;
+ if ((q->queue_type == QDIO_IQDIO_QFMT) &&
+ (no_output_qs > 1) &&
+ (i == no_output_qs-1))
+ q->queue_type = QDIO_IQDIO_QFMT_ASYNCH;
q->int_parm=int_parm;
q->is_input_q=0;
q->schid = irq_ptr->schid;
{
QDIO_DBF_TEXT4(0,trace,"thin_int");
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.thinints++;
- perf_stats.start_time_inbound=NOW;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats) {
+ perf_stats.thinints++;
+ perf_stats.start_time_inbound=NOW;
+ }
/* SVS only when needed:
* issue SVS to benefit from iqdio interrupt avoidance
QDIO_DBF_HEX0(0,sense,irb,QDIO_DBF_SENSE_LEN);
QDIO_PRINT_WARN("sense data available on qdio channel.\n");
- HEXDUMP16(WARN,"irb: ",irb);
- HEXDUMP16(WARN,"sense data: ",irb->ecw);
+ QDIO_HEXDUMP16(WARN,"irb: ",irb);
+ QDIO_HEXDUMP16(WARN,"sense data: ",irb->ecw);
}
}
int i;
struct qdio_q *q;
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.pcis++;
- perf_stats.start_time_inbound=NOW;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats) {
+ perf_stats.pcis++;
+ perf_stats.start_time_inbound=NOW;
+ }
for (i=0;i<irq_ptr->no_input_qs;i++) {
q=irq_ptr->input_qs[i];
if (q->is_input_q&QDIO_FLAG_NO_INPUT_INTERRUPT_CONTEXT)
qdio_mark_q(q);
else {
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.tl_runs--;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ perf_stats.tl_runs--;
__qdio_inbound_processing(q);
}
}
return;
for (i=0;i<irq_ptr->no_output_qs;i++) {
q=irq_ptr->output_qs[i];
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.tl_runs--;
-#endif /* QDIO_PERFORMANCE_STATS */
if (qdio_is_outbound_q_done(q))
continue;
+ if (qdio_performance_stats)
+ perf_stats.tl_runs--;
if (!irq_ptr->sync_done_on_outb_pcis)
SYNC_MEMORY;
__qdio_outbound_processing(q);
}
static void
-qdio_call_shutdown(void *data)
+qdio_call_shutdown(struct work_struct *work)
{
+ struct ccw_device_private *priv;
struct ccw_device *cdev;
- cdev = (struct ccw_device *)data;
+ priv = container_of(work, struct ccw_device_private, kick_work);
+ cdev = priv->cdev;
qdio_shutdown(cdev, QDIO_FLAG_CLEANUP_USING_CLEAR);
put_device(&cdev->dev);
}
if (get_device(&cdev->dev)) {
/* Can't call shutdown from interrupt context. */
PREPARE_WORK(&cdev->private->kick_work,
- qdio_call_shutdown, (void *)cdev);
+ qdio_call_shutdown);
queue_work(ccw_device_work, &cdev->private->kick_work);
}
break;
QDIO_DBF_TEXT0(0,setup,"getssqd");
qdioac = 0;
- ssqd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+ ssqd_area = mempool_alloc(qdio_mempool_scssc, GFP_ATOMIC);
if (!ssqd_area) {
QDIO_PRINT_WARN("Could not get memory for chsc. Using all " \
"SIGAs for sch x%x.\n", irq_ptr->schid.sch_no);
out:
qdio_check_subchannel_qebsm(irq_ptr, qdioac,
ssqd_area->sch_token);
- free_page ((unsigned long) ssqd_area);
+ mempool_free(ssqd_area, qdio_mempool_scssc);
irq_ptr->qdioac = qdioac;
}
virt_to_phys((volatile void *)irq_ptr->dev_st_chg_ind);
}
- scssc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+ scssc_area = mempool_alloc(qdio_mempool_scssc, GFP_ATOMIC);
if (!scssc_area) {
QDIO_PRINT_WARN("No memory for setting indicators on " \
"subchannel 0.%x.%x.\n",
QDIO_DBF_HEX2(0,setup,&real_addr_dev_st_chg_ind,sizeof(unsigned long));
result = 0;
out:
- free_page ((unsigned long) scssc_area);
+ mempool_free(scssc_area, qdio_mempool_scssc);
return result;
}
if (!irq_ptr->is_thinint_irq)
return -ENODEV;
- scsscf_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
+ scsscf_area = mempool_alloc(qdio_mempool_scssc, GFP_ATOMIC);
if (!scsscf_area) {
QDIO_PRINT_WARN("No memory for setting delay target on " \
"subchannel 0.%x.%x.\n",
QDIO_DBF_HEX2(0,trace,&delay_target,sizeof(unsigned long));
result = 0; /* not critical */
out:
- free_page ((unsigned long) scsscf_area);
+ mempool_free(scsscf_area, qdio_mempool_scssc);
return result;
}
QDIO_DBF_TEXT1(0,trace,dbf_text);
QDIO_DBF_TEXT0(0,setup,dbf_text);
- cdev->private->qdio_data = 0;
+ cdev->private->qdio_data = NULL;
up(&irq_ptr->setting_up_sema);
irq_ptr = cdev->private->qdio_data;
- sprintf(dbf_text,"qehi%4x",cdev->private->sch_no);
+ sprintf(dbf_text,"qehi%4x",cdev->private->schid.sch_no);
QDIO_DBF_TEXT0(0,setup,dbf_text);
QDIO_DBF_TEXT0(0,trace,dbf_text);
int rc;
char dbf_text[15];
- sprintf(dbf_text,"qini%4x",init_data->cdev->private->sch_no);
+ sprintf(dbf_text,"qini%4x",init_data->cdev->private->schid.sch_no);
QDIO_DBF_TEXT0(0,setup,dbf_text);
QDIO_DBF_TEXT0(0,trace,dbf_text);
struct qdio_irq *irq_ptr;
char dbf_text[15];
- sprintf(dbf_text,"qalc%4x",init_data->cdev->private->sch_no);
+ sprintf(dbf_text,"qalc%4x",init_data->cdev->private->schid.sch_no);
QDIO_DBF_TEXT0(0,setup,dbf_text);
QDIO_DBF_TEXT0(0,trace,dbf_text);
if ( (init_data->no_input_qs>QDIO_MAX_QUEUES_PER_IRQ) ||
qdio_allocate_do_dbf(init_data);
/* create irq */
- irq_ptr=kmalloc(sizeof(struct qdio_irq), GFP_KERNEL | GFP_DMA);
+ irq_ptr = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
QDIO_DBF_TEXT0(0,setup,"irq_ptr:");
QDIO_DBF_HEX0(0,setup,&irq_ptr,sizeof(void*));
return -ENOMEM;
}
- memset(irq_ptr,0,sizeof(struct qdio_irq));
-
init_MUTEX(&irq_ptr->setting_up_sema);
/* QDR must be in DMA area since CCW data address is only 32 bit */
irq_ptr->qdr=kmalloc(sizeof(struct qdr), GFP_KERNEL | GFP_DMA);
if (!(irq_ptr->qdr)) {
- kfree(irq_ptr);
+ free_page((unsigned long) irq_ptr);
QDIO_PRINT_ERR("kmalloc of irq_ptr->qdr failed!\n");
return -ENOMEM;
}
tiqdio_set_delay_target(irq_ptr,TIQDIO_DELAY_TARGET);
}
- sprintf(dbf_text,"qest%4x",cdev->private->sch_no);
+ sprintf(dbf_text,"qest%4x",cdev->private->schid.sch_no);
QDIO_DBF_TEXT0(0,setup,dbf_text);
QDIO_DBF_TEXT0(0,trace,dbf_text);
if ((used_elements+count==QDIO_MAX_BUFFERS_PER_Q)&&
(callflags&QDIO_FLAG_UNDER_INTERRUPT))
- atomic_swap(&q->polling,0);
+ atomic_xchg(&q->polling,0);
if (used_elements)
return;
struct qdio_irq *irq = (struct qdio_irq *) q->irq_ptr;
/* This is the outbound handling of queues */
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.start_time_outbound=NOW;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ perf_stats.start_time_outbound=NOW;
qdio_do_qdio_fill_output(q,qidx,count,buffers);
used_elements=atomic_add_return(count, &q->number_of_buffers_used) - count;
if (callflags&QDIO_FLAG_DONT_SIGA) {
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.outbound_time+=NOW-perf_stats.start_time_outbound;
- perf_stats.outbound_cnt++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats) {
+ perf_stats.outbound_time+=NOW-perf_stats.start_time_outbound;
+ perf_stats.outbound_cnt++;
+ }
return;
}
if (q->is_iqdio_q) {
qdio_kick_outbound_q(q);
} else {
QDIO_DBF_TEXT3(0,trace, "fast-req");
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.fast_reqs++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats)
+ perf_stats.fast_reqs++;
}
}
/*
__qdio_outbound_processing(q);
}
-#ifdef QDIO_PERFORMANCE_STATS
- perf_stats.outbound_time+=NOW-perf_stats.start_time_outbound;
- perf_stats.outbound_cnt++;
-#endif /* QDIO_PERFORMANCE_STATS */
+ if (qdio_performance_stats) {
+ perf_stats.outbound_time+=NOW-perf_stats.start_time_outbound;
+ perf_stats.outbound_cnt++;
+ }
}
/* count must be 1 in iqdio */
#ifdef CONFIG_QDIO_DEBUG
char dbf_text[20];
- sprintf(dbf_text,"doQD%04x",cdev->private->sch_no);
+ sprintf(dbf_text,"doQD%04x",cdev->private->schid.sch_no);
QDIO_DBF_TEXT3(0,trace,dbf_text);
#endif /* CONFIG_QDIO_DEBUG */
return 0;
}
-#ifdef QDIO_PERFORMANCE_STATS
static int
qdio_perf_procfile_read(char *buffer, char **buffer_location, off_t offset,
int buffer_length, int *eof, void *data)
_OUTP_IT("i_p_nc/c=%lu/%lu\n",i_p_nc,i_p_c);
_OUTP_IT("ii_p_nc/c=%lu/%lu\n",ii_p_nc,ii_p_c);
_OUTP_IT("o_p_nc/c=%lu/%lu\n",o_p_nc,o_p_c);
- _OUTP_IT("Number of tasklet runs (total) : %u\n",
+ _OUTP_IT("Number of tasklet runs (total) : %lu\n",
perf_stats.tl_runs);
_OUTP_IT("\n");
- _OUTP_IT("Number of SIGA sync's issued : %u\n",
+ _OUTP_IT("Number of SIGA sync's issued : %lu\n",
perf_stats.siga_syncs);
- _OUTP_IT("Number of SIGA in's issued : %u\n",
+ _OUTP_IT("Number of SIGA in's issued : %lu\n",
perf_stats.siga_ins);
- _OUTP_IT("Number of SIGA out's issued : %u\n",
+ _OUTP_IT("Number of SIGA out's issued : %lu\n",
perf_stats.siga_outs);
- _OUTP_IT("Number of PCIs caught : %u\n",
+ _OUTP_IT("Number of PCIs caught : %lu\n",
perf_stats.pcis);
- _OUTP_IT("Number of adapter interrupts caught : %u\n",
+ _OUTP_IT("Number of adapter interrupts caught : %lu\n",
perf_stats.thinints);
- _OUTP_IT("Number of fast requeues (outg. SBALs w/o SIGA) : %u\n",
+ _OUTP_IT("Number of fast requeues (outg. SBALs w/o SIGA) : %lu\n",
perf_stats.fast_reqs);
_OUTP_IT("\n");
- _OUTP_IT("Total time of all inbound actions (us) incl. UL : %u\n",
+ _OUTP_IT("Total time of all inbound actions (us) incl. UL : %lu\n",
perf_stats.inbound_time);
- _OUTP_IT("Number of inbound transfers : %u\n",
+ _OUTP_IT("Number of inbound transfers : %lu\n",
perf_stats.inbound_cnt);
- _OUTP_IT("Total time of all outbound do_QDIOs (us) : %u\n",
+ _OUTP_IT("Total time of all outbound do_QDIOs (us) : %lu\n",
perf_stats.outbound_time);
- _OUTP_IT("Number of do_QDIOs outbound : %u\n",
+ _OUTP_IT("Number of do_QDIOs outbound : %lu\n",
perf_stats.outbound_cnt);
_OUTP_IT("\n");
}
static struct proc_dir_entry *qdio_perf_proc_file;
-#endif /* QDIO_PERFORMANCE_STATS */
static void
qdio_add_procfs_entry(void)
{
-#ifdef QDIO_PERFORMANCE_STATS
proc_perf_file_registration=0;
qdio_perf_proc_file=create_proc_entry(QDIO_PERF,
S_IFREG|0444,&proc_root);
QDIO_PRINT_WARN("was not able to register perf. " \
"proc-file (%i).\n",
proc_perf_file_registration);
-#endif /* QDIO_PERFORMANCE_STATS */
}
static void
qdio_remove_procfs_entry(void)
{
-#ifdef QDIO_PERFORMANCE_STATS
perf_stats.tl_runs=0;
if (!proc_perf_file_registration) /* means if it went ok earlier */
remove_proc_entry(QDIO_PERF,&proc_root);
-#endif /* QDIO_PERFORMANCE_STATS */
}
+/**
+ * attributes in sysfs
+ *****************************************************************************/
+
+static ssize_t
+qdio_performance_stats_show(struct bus_type *bus, char *buf)
+{
+ return sprintf(buf, "%i\n", qdio_performance_stats ? 1 : 0);
+}
+
+static ssize_t
+qdio_performance_stats_store(struct bus_type *bus, const char *buf, size_t count)
+{
+ char *tmp;
+ int i;
+
+ i = simple_strtoul(buf, &tmp, 16);
+ if ((i == 0) || (i == 1)) {
+ if (i == qdio_performance_stats)
+ return count;
+ qdio_performance_stats = i;
+ if (i==0) {
+ /* reset perf. stat. info */
+ i_p_nc = 0;
+ i_p_c = 0;
+ ii_p_nc = 0;
+ ii_p_c = 0;
+ o_p_nc = 0;
+ o_p_c = 0;
+ memset(&perf_stats, 0, sizeof(struct qdio_perf_stats));
+ }
+ } else {
+ QDIO_PRINT_WARN("QDIO performance_stats: write 0 or 1 to this file!\n");
+ return -EINVAL;
+ }
+ return count;
+}
+
+static BUS_ATTR(qdio_performance_stats, 0644, qdio_performance_stats_show,
+ qdio_performance_stats_store);
+
static void
tiqdio_register_thinints(void)
{
for (i=1;i<INDICATORS_PER_CACHELINE;i++)
indicator_used[i]=0;
- indicators=(__u32*)kmalloc(sizeof(__u32)*(INDICATORS_PER_CACHELINE),
+ indicators = kzalloc(sizeof(__u32)*(INDICATORS_PER_CACHELINE),
GFP_KERNEL);
- if (!indicators) return -ENOMEM;
- memset(indicators,0,sizeof(__u32)*(INDICATORS_PER_CACHELINE));
+ if (!indicators)
+ return -ENOMEM;
return 0;
}
kfree(indicators);
}
+
static void
qdio_unregister_dbf_views(void)
{
return -ENOMEM;
}
+static void *qdio_mempool_alloc(gfp_t gfp_mask, void *size)
+{
+ return (void *) get_zeroed_page(gfp_mask|GFP_DMA);
+}
+
+static void qdio_mempool_free(void *element, void *size)
+{
+ free_page((unsigned long) element);
+}
+
static int __init
init_QDIO(void)
{
int res;
-#ifdef QDIO_PERFORMANCE_STATS
void *ptr;
-#endif /* QDIO_PERFORMANCE_STATS */
printk("qdio: loading %s\n",version);
return res;
QDIO_DBF_TEXT0(0,setup,"initQDIO");
+ res = bus_create_file(&ccw_bus_type, &bus_attr_qdio_performance_stats);
-#ifdef QDIO_PERFORMANCE_STATS
- memset((void*)&perf_stats,0,sizeof(perf_stats));
+ memset((void*)&perf_stats,0,sizeof(perf_stats));
QDIO_DBF_TEXT0(0,setup,"perfstat");
ptr=&perf_stats;
QDIO_DBF_HEX0(0,setup,&ptr,sizeof(void*));
-#endif /* QDIO_PERFORMANCE_STATS */
qdio_add_procfs_entry();
+ qdio_mempool_scssc = mempool_create(QDIO_MEMPOOL_SCSSC_ELEMENTS,
+ qdio_mempool_alloc,
+ qdio_mempool_free, NULL);
+
if (tiqdio_check_chsc_availability())
QDIO_PRINT_ERR("Not all CHSCs supported. Continuing.\n");
qdio_remove_procfs_entry();
qdio_release_qdio_memory();
qdio_unregister_dbf_views();
-
+ mempool_destroy(qdio_mempool_scssc);
+ bus_remove_file(&ccw_bus_type, &bus_attr_qdio_performance_stats);
printk("qdio: %s: module removed\n",version);
}