Skip to content
Snippets Groups Projects
intel-gptc-timer.c 27.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • Ma, Hua's avatar
    Ma, Hua committed
    			timer->yield_pin = param->yield_pin;
    			pr_debug("gptc %d timer %d ht_yield register @cpu%d\n",
    				 timer->gptcid, timer->tid, timer->cpuid);
    
    			/* enable this irq and mark this as gptc_yield_irq */
    			ret = request_irq(timer->irq, tc_dummy_isr, 0,
    					  "gptc_yield_irq", NULL);
    			if (ret) {
    				pr_err("%s: failed to request gptu irq - %d",
    				       __func__, timer->irq);
    				return -ENOENT;
    			}
    
    			gptc_irq_unmask(timer);
    			ret = gic_yield_setup(cpu, param->yield_pin,
    					      timer->irq);
    			if (ret) {
    				pr_err("Yield Setup Fail:\n");
    				return -ENOENT;
    			}
    
    			pr_debug("Yield setup passed, gptc_irq = %d\n",
    				 timer->irq);
    
    			tc_num = vmb_tc_alloc(cpu);
    			if (tc_num < 0) {
    				pr_err("%s: failed to request vmb tc - %d",
    				       __func__, tc_num);
    				return -ENOENT;
    			}
    			memset(&tc_launch, 0, sizeof(tc_launch));
    			tc_launch.tc_num = tc_num;
    			tc_launch.start_addr = (u32)&tc_thread;
    			tc_launch.sp = (u32)&tc_thread_stack +
    					GPTC_TC_THREAD_STACK_SIZE -
    					GPTC_TC_THREAD_STACK_RESERVED_SIZE;
    			tc_launch.sp &= ~0xF;  /*padding to 16 bytes*/
    			tc_launch.gp = (u32)&tc_thread_gp;
    			tc_launch.priv_info = (u32)timer;
    			ret = vmb_run_tc(cpu, &tc_launch);
    			if (ret) {
    				pr_err("Failed to run the vmb TC.\n");
    				return -ENOENT;
    			}
    
    			interval = param->interval;
    			/* interval is the unit of microsecond */
    			cycles = interval * (timer->frequency / 1000000);
    			gptc_mode_setup(timer, false);
    			gptc_reload_counter(timer, cycles);
    			gptc_reload_and_run(timer);
    
    			return 0;
    		}
    		pr_err("only one ht_yield timer can be supported!\n");
    		return -EINVAL;
    	}
    	return -EINVAL;
    }
    #else
    int gptc_ht_yield_init(struct gptc_ht_yield *param, void *call_back,
    		       void *call_back_param)
    {
    	return -EINVAL;
    }
    #endif
    EXPORT_SYMBOL(gptc_ht_yield_init);
    
    int gptc_ht_yield_interval(u32 interval)
    {
    	unsigned long cycles;
    	struct gptc_timer *timer;
    
    	if (interval == 0) {
    		pr_err("Bad parameter.\n");
    		return -EINVAL;
    	}
    	list_for_each_entry(timer, &gptc_ht_yield_list, ht_yield) {
    		if (timer->used) {
    			cycles = interval * (timer->frequency / 1000000);
    			gptc_stop_counter(timer);
    			gptc_reload_counter(timer, cycles);
    			gptc_reload_and_run(timer);
    		}
    	}
    	return 0;
    }
    EXPORT_SYMBOL(gptc_ht_yield_interval);
    
    
    static void *gptc_seq_start(struct seq_file *s, loff_t *pos)
    {
    	if (list_empty(&gptc_list))
    		return NULL;
    
    	return seq_list_start(&gptc_list, *pos);
    }
    
    static void *gptc_seq_next(struct seq_file *s, void *v, loff_t *pos)
    {
    	return seq_list_next(v, &gptc_list, pos);
    }
    
    static void gptc_seq_stop(struct seq_file *s, void *v)
    {
    }
    
    static int gptc_seq_show(struct seq_file *s, void *v)
    {
    	int i = 0;
    	struct gptc *gptc;
    	struct gptc_timer *timer;
    
    	gptc = list_entry(v, struct gptc, next);
    
    
    	seq_printf(s, "GPTC%d base %p phy %lx freq %d\n",
    		   gptc->id, gptc->base, gptc->phy_base, gptc->fpifreq);
    
    	seq_printf(s, "CLC %08x ID %08x IRNEN %08x IRNICR %08x IRNCR %08x\n",
    
    		   ioread32(gptc->base + GPTC_CLC),
    		   ioread32(gptc->base + GPTC_ID),
    		   ioread32(gptc->base + GPTC_IRNEN),
    		   ioread32(gptc->base + GPTC_IRNICR),
    		   ioread32(gptc->base + GPTC_IRNCR));
    
    
    	list_for_each_entry(timer, &gptc->parent, child) {
    
    leichuan's avatar
    leichuan committed
    		seq_printf(s, "\ttimer%d base %p freq %d tid %d cpuid %d irq %d clk %s %s\n",
    
    			   i, timer->base, timer->frequency, timer->tid,
    			   timer->cpuid, timer->irq,
    			   timer_type_to_str(timer->type),
    			   timer->used ? "used" : "unused");
    
    leichuan's avatar
    leichuan committed
    		seq_printf(s, "\tCON %08x RUN %08x RLD %08x CNT %08x\n",
    
    			   gptc_readl(timer, GPTC_CON(i)),
    			   gptc_readl(timer, GPTC_RUN(i)),
    			   gptc_readl(timer, GPTC_RLD(i)),
    			   gptc_readl(timer, GPTC_CNT(i)));
    
    		i++;
    	}
    	seq_putc(s, '\n');
    	return 0;
    }
    
    static const struct seq_operations gptc_seq_ops = {
    	.start = gptc_seq_start,
    	.next = gptc_seq_next,
    	.stop = gptc_seq_stop,
    	.show = gptc_seq_show,
    };
    
    static int gptc_open(struct inode *inode, struct file *file)
    {
    	int err;
    
    	err = seq_open(file, &gptc_seq_ops);
    	if (err)
    		return err;
    	return 0;
    }
    
    static const struct file_operations gptc_ops = {
    	.owner = THIS_MODULE,
    	.open = gptc_open,
    	.read = seq_read,
    	.llseek = seq_lseek,
    	.release = seq_release,
    };
    
    static int gptc_debugfs_init(void)
    {
    	struct dentry *file;
    	struct dentry *debugfs;
    
    	debugfs = debugfs_create_dir("gptc", NULL);
    	if (!debugfs)
    		return -ENOMEM;
    
    	file = debugfs_create_file("status", 0444, debugfs, NULL, &gptc_ops);
    	if (!file)
    		goto remove;
    
    	return 0;
    remove:
    	debugfs_remove_recursive(debugfs);
    	debugfs = NULL;
    	return -ENOMEM;
    }
    late_initcall(gptc_debugfs_init);