0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022 #include <linux/module.h>
0023 #include <linux/stddef.h> /* for offsetof() */
0024 #include <linux/init.h>
0025 #include <linux/types.h>
0026 #include <linux/ioport.h>
0027 #include <linux/utsname.h>
0028 #include <linux/capability.h>
0029 #include <linux/delay.h>
0030 #include <linux/netdevice.h>
0031 #include <linux/inetdevice.h>
0032 #include <linux/in.h>
0033 #include <linux/interrupt.h>
0034 #include <linux/kernel_stat.h>
0035 #include <linux/reboot.h>
0036 #include <linux/proc_fs.h>
0037 #include <linux/seq_file.h>
0038 #include <linux/ctype.h>
0039 #include <linux/blkdev.h>
0040 #include <linux/workqueue.h>
0041 #include <linux/rcupdate.h>
0042 #include <asm/io.h>
0043 #include <asm/processor.h>
0044 #include <asm/hardware.h>
0045 #include <asm/param.h> /* HZ */
0046 #include <asm/led.h>
0047 #include <asm/pdc.h>
0048 #include <linux/uaccess.h>
0049
0050
0051
0052
0053
0054
0055
0056 static int led_type __read_mostly = -1;
0057 static unsigned char lastleds;
0058 static unsigned int led_heartbeat __read_mostly = 1;
0059 static unsigned int led_diskio __read_mostly = 1;
0060 static unsigned int led_lanrxtx __read_mostly = 1;
0061 static char lcd_text[32] __read_mostly;
0062 static char lcd_text_default[32] __read_mostly;
0063 static int lcd_no_led_support __read_mostly = 0;
0064
0065
0066 static struct workqueue_struct *led_wq;
0067 static void led_work_func(struct work_struct *);
0068 static DECLARE_DELAYED_WORK(led_task, led_work_func);
0069
0070 #if 0
0071 #define DPRINTK(x) printk x
0072 #else
0073 #define DPRINTK(x)
0074 #endif
0075
0076 struct lcd_block {
0077 unsigned char command;
0078 unsigned char on;
0079 unsigned char off;
0080 };
0081
0082
0083
0084
0085 struct pdc_chassis_lcd_info_ret_block {
0086 unsigned long model:16;
0087 unsigned long lcd_width:16;
0088 unsigned long lcd_cmd_reg_addr;
0089 unsigned long lcd_data_reg_addr;
0090 unsigned int min_cmd_delay;
0091 unsigned char reset_cmd1;
0092 unsigned char reset_cmd2;
0093 unsigned char act_enable;
0094 struct lcd_block heartbeat;
0095 struct lcd_block disk_io;
0096 struct lcd_block lan_rcv;
0097 struct lcd_block lan_tx;
0098 char _pad;
0099 };
0100
0101
0102
0103 #define KITTYHAWK_LCD_CMD F_EXTEND(0xf0190000UL)
0104 #define KITTYHAWK_LCD_DATA (KITTYHAWK_LCD_CMD+1)
0105
0106
0107
0108 static struct pdc_chassis_lcd_info_ret_block
0109 lcd_info __attribute__((aligned(8))) __read_mostly =
0110 {
0111 .model = DISPLAY_MODEL_LCD,
0112 .lcd_width = 16,
0113 .lcd_cmd_reg_addr = KITTYHAWK_LCD_CMD,
0114 .lcd_data_reg_addr = KITTYHAWK_LCD_DATA,
0115 .min_cmd_delay = 80,
0116 .reset_cmd1 = 0x80,
0117 .reset_cmd2 = 0xc0,
0118 };
0119
0120
0121
0122 #define LCD_CMD_REG lcd_info.lcd_cmd_reg_addr
0123 #define LCD_DATA_REG lcd_info.lcd_data_reg_addr
0124 #define LED_DATA_REG lcd_info.lcd_cmd_reg_addr
0125
0126 #define LED_HASLCD 1
0127 #define LED_NOLCD 0
0128
0129
0130 static int start_task(void)
0131 {
0132
0133 if (led_type == LED_HASLCD) lcd_print( lcd_text_default );
0134
0135
0136 if (lcd_no_led_support) return 0;
0137
0138
0139 led_wq = create_singlethread_workqueue("led_wq");
0140 queue_delayed_work(led_wq, &led_task, 0);
0141
0142 return 0;
0143 }
0144
0145 device_initcall(start_task);
0146
0147
0148 static void (*led_func_ptr) (unsigned char) __read_mostly;
0149
0150 #ifdef CONFIG_PROC_FS
0151 static int led_proc_show(struct seq_file *m, void *v)
0152 {
0153 switch ((long)m->private)
0154 {
0155 case LED_NOLCD:
0156 seq_printf(m, "Heartbeat: %d\n", led_heartbeat);
0157 seq_printf(m, "Disk IO: %d\n", led_diskio);
0158 seq_printf(m, "LAN Rx/Tx: %d\n", led_lanrxtx);
0159 break;
0160 case LED_HASLCD:
0161 seq_printf(m, "%s\n", lcd_text);
0162 break;
0163 default:
0164 return 0;
0165 }
0166 return 0;
0167 }
0168
0169 static int led_proc_open(struct inode *inode, struct file *file)
0170 {
0171 return single_open(file, led_proc_show, pde_data(inode));
0172 }
0173
0174
0175 static ssize_t led_proc_write(struct file *file, const char __user *buf,
0176 size_t count, loff_t *pos)
0177 {
0178 void *data = pde_data(file_inode(file));
0179 char *cur, lbuf[32];
0180 int d;
0181
0182 if (!capable(CAP_SYS_ADMIN))
0183 return -EACCES;
0184
0185 if (count >= sizeof(lbuf))
0186 count = sizeof(lbuf)-1;
0187
0188 if (copy_from_user(lbuf, buf, count))
0189 return -EFAULT;
0190 lbuf[count] = 0;
0191
0192 cur = lbuf;
0193
0194 switch ((long)data)
0195 {
0196 case LED_NOLCD:
0197 d = *cur++ - '0';
0198 if (d != 0 && d != 1) goto parse_error;
0199 led_heartbeat = d;
0200
0201 if (*cur++ != ' ') goto parse_error;
0202
0203 d = *cur++ - '0';
0204 if (d != 0 && d != 1) goto parse_error;
0205 led_diskio = d;
0206
0207 if (*cur++ != ' ') goto parse_error;
0208
0209 d = *cur++ - '0';
0210 if (d != 0 && d != 1) goto parse_error;
0211 led_lanrxtx = d;
0212
0213 break;
0214 case LED_HASLCD:
0215 if (*cur && cur[strlen(cur)-1] == '\n')
0216 cur[strlen(cur)-1] = 0;
0217 if (*cur == 0)
0218 cur = lcd_text_default;
0219 lcd_print(cur);
0220 break;
0221 default:
0222 return 0;
0223 }
0224
0225 return count;
0226
0227 parse_error:
0228 if ((long)data == LED_NOLCD)
0229 printk(KERN_CRIT "Parse error: expect \"n n n\" (n == 0 or 1) for heartbeat,\ndisk io and lan tx/rx indicators\n");
0230 return -EINVAL;
0231 }
0232
0233 static const struct proc_ops led_proc_ops = {
0234 .proc_open = led_proc_open,
0235 .proc_read = seq_read,
0236 .proc_lseek = seq_lseek,
0237 .proc_release = single_release,
0238 .proc_write = led_proc_write,
0239 };
0240
0241 static int __init led_create_procfs(void)
0242 {
0243 struct proc_dir_entry *proc_pdc_root = NULL;
0244 struct proc_dir_entry *ent;
0245
0246 if (led_type == -1) return -1;
0247
0248 proc_pdc_root = proc_mkdir("pdc", NULL);
0249 if (!proc_pdc_root) return -1;
0250
0251 if (!lcd_no_led_support)
0252 {
0253 ent = proc_create_data("led", 0644, proc_pdc_root,
0254 &led_proc_ops, (void *)LED_NOLCD);
0255 if (!ent) return -1;
0256 }
0257
0258 if (led_type == LED_HASLCD)
0259 {
0260 ent = proc_create_data("lcd", 0644, proc_pdc_root,
0261 &led_proc_ops, (void *)LED_HASLCD);
0262 if (!ent) return -1;
0263 }
0264
0265 return 0;
0266 }
0267 #endif
0268
0269
0270
0271
0272
0273
0274 #define LED_DATA 0x01
0275 #define LED_STROBE 0x02
0276 static void led_ASP_driver(unsigned char leds)
0277 {
0278 int i;
0279
0280 leds = ~leds;
0281 for (i = 0; i < 8; i++) {
0282 unsigned char value;
0283 value = (leds & 0x80) >> 7;
0284 gsc_writeb( value, LED_DATA_REG );
0285 gsc_writeb( value | LED_STROBE, LED_DATA_REG );
0286 leds <<= 1;
0287 }
0288 }
0289
0290
0291
0292
0293
0294
0295
0296 static void led_LASI_driver(unsigned char leds)
0297 {
0298 leds = ~leds;
0299 gsc_writeb( leds, LED_DATA_REG );
0300 }
0301
0302
0303
0304
0305
0306
0307
0308 static void led_LCD_driver(unsigned char leds)
0309 {
0310 static int i;
0311 static unsigned char mask[4] = { LED_HEARTBEAT, LED_DISK_IO,
0312 LED_LAN_RCV, LED_LAN_TX };
0313
0314 static struct lcd_block * blockp[4] = {
0315 &lcd_info.heartbeat,
0316 &lcd_info.disk_io,
0317 &lcd_info.lan_rcv,
0318 &lcd_info.lan_tx
0319 };
0320
0321
0322 unsigned int msec_cmd_delay = 1 + (lcd_info.min_cmd_delay / 1000);
0323
0324 for (i=0; i<4; ++i)
0325 {
0326 if ((leds & mask[i]) != (lastleds & mask[i]))
0327 {
0328 gsc_writeb( blockp[i]->command, LCD_CMD_REG );
0329 msleep(msec_cmd_delay);
0330
0331 gsc_writeb( leds & mask[i] ? blockp[i]->on :
0332 blockp[i]->off, LCD_DATA_REG );
0333 msleep(msec_cmd_delay);
0334 }
0335 }
0336 }
0337
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347 static __inline__ int led_get_net_activity(void)
0348 {
0349 #ifndef CONFIG_NET
0350 return 0;
0351 #else
0352 static u64 rx_total_last, tx_total_last;
0353 u64 rx_total, tx_total;
0354 struct net_device *dev;
0355 int retval;
0356
0357 rx_total = tx_total = 0;
0358
0359
0360 rcu_read_lock();
0361 for_each_netdev_rcu(&init_net, dev) {
0362 const struct rtnl_link_stats64 *stats;
0363 struct rtnl_link_stats64 temp;
0364 struct in_device *in_dev = __in_dev_get_rcu(dev);
0365 if (!in_dev || !in_dev->ifa_list)
0366 continue;
0367 if (ipv4_is_loopback(in_dev->ifa_list->ifa_local))
0368 continue;
0369 stats = dev_get_stats(dev, &temp);
0370 rx_total += stats->rx_packets;
0371 tx_total += stats->tx_packets;
0372 }
0373 rcu_read_unlock();
0374
0375 retval = 0;
0376
0377 if (rx_total != rx_total_last) {
0378 rx_total_last = rx_total;
0379 retval |= LED_LAN_RCV;
0380 }
0381
0382 if (tx_total != tx_total_last) {
0383 tx_total_last = tx_total;
0384 retval |= LED_LAN_TX;
0385 }
0386
0387 return retval;
0388 #endif
0389 }
0390
0391
0392
0393
0394
0395
0396
0397
0398
0399 static __inline__ int led_get_diskio_activity(void)
0400 {
0401 static unsigned long last_pgpgin, last_pgpgout;
0402 unsigned long events[NR_VM_EVENT_ITEMS];
0403 int changed;
0404
0405 all_vm_events(events);
0406
0407
0408
0409 changed = (events[PGPGIN] != last_pgpgin) ||
0410 (events[PGPGOUT] != last_pgpgout);
0411 last_pgpgin = events[PGPGIN];
0412 last_pgpgout = events[PGPGOUT];
0413
0414 return (changed ? LED_DISK_IO : 0);
0415 }
0416
0417
0418
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429 #define HEARTBEAT_LEN (HZ*10/100)
0430 #define HEARTBEAT_2ND_RANGE_START (HZ*28/100)
0431 #define HEARTBEAT_2ND_RANGE_END (HEARTBEAT_2ND_RANGE_START + HEARTBEAT_LEN)
0432
0433 #define LED_UPDATE_INTERVAL (1 + (HZ*19/1000))
0434
0435 static void led_work_func (struct work_struct *unused)
0436 {
0437 static unsigned long last_jiffies;
0438 static unsigned long count_HZ;
0439 unsigned char currentleds = 0;
0440
0441
0442 if (!led_func_ptr)
0443 return;
0444
0445
0446 count_HZ += jiffies - last_jiffies;
0447 last_jiffies = jiffies;
0448 if (count_HZ >= HZ)
0449 count_HZ = 0;
0450
0451 if (likely(led_heartbeat))
0452 {
0453
0454
0455
0456 if (count_HZ < HEARTBEAT_LEN ||
0457 (count_HZ >= HEARTBEAT_2ND_RANGE_START &&
0458 count_HZ < HEARTBEAT_2ND_RANGE_END))
0459 currentleds |= LED_HEARTBEAT;
0460 }
0461
0462 if (likely(led_lanrxtx)) currentleds |= led_get_net_activity();
0463 if (likely(led_diskio)) currentleds |= led_get_diskio_activity();
0464
0465
0466 if (unlikely(oops_in_progress)) {
0467 if (boot_cpu_data.cpu_type >= pcxl2) {
0468
0469
0470 currentleds = (count_HZ <= (HZ/2)) ? 0 : 0xff;
0471 } else {
0472
0473 if (count_HZ <= (HZ/2))
0474 currentleds &= ~(LED4|LED5|LED6|LED7);
0475 else
0476 currentleds |= (LED4|LED5|LED6|LED7);
0477 }
0478 }
0479
0480 if (currentleds != lastleds)
0481 {
0482 led_func_ptr(currentleds);
0483 lastleds = currentleds;
0484 }
0485
0486 queue_delayed_work(led_wq, &led_task, LED_UPDATE_INTERVAL);
0487 }
0488
0489
0490
0491
0492
0493
0494
0495
0496
0497 static int led_halt(struct notifier_block *, unsigned long, void *);
0498
0499 static struct notifier_block led_notifier = {
0500 .notifier_call = led_halt,
0501 };
0502 static int notifier_disabled = 0;
0503
0504 static int led_halt(struct notifier_block *nb, unsigned long event, void *buf)
0505 {
0506 char *txt;
0507
0508 if (notifier_disabled)
0509 return NOTIFY_OK;
0510
0511 notifier_disabled = 1;
0512 switch (event) {
0513 case SYS_RESTART: txt = "SYSTEM RESTART";
0514 break;
0515 case SYS_HALT: txt = "SYSTEM HALT";
0516 break;
0517 case SYS_POWER_OFF: txt = "SYSTEM POWER OFF";
0518 break;
0519 default: return NOTIFY_DONE;
0520 }
0521
0522
0523 if (led_wq) {
0524 cancel_delayed_work_sync(&led_task);
0525 destroy_workqueue(led_wq);
0526 led_wq = NULL;
0527 }
0528
0529 if (lcd_info.model == DISPLAY_MODEL_LCD)
0530 lcd_print(txt);
0531 else
0532 if (led_func_ptr)
0533 led_func_ptr(0xff);
0534
0535 return NOTIFY_OK;
0536 }
0537
0538
0539
0540
0541
0542
0543
0544
0545
0546 int __init register_led_driver(int model, unsigned long cmd_reg, unsigned long data_reg)
0547 {
0548 static int initialized;
0549
0550 if (initialized || !data_reg)
0551 return 1;
0552
0553 lcd_info.model = model;
0554 LCD_CMD_REG = (cmd_reg == LED_CMD_REG_NONE) ? 0 : cmd_reg;
0555
0556 switch (lcd_info.model) {
0557 case DISPLAY_MODEL_LCD:
0558 LCD_DATA_REG = data_reg;
0559 printk(KERN_INFO "LCD display at %lx,%lx registered\n",
0560 LCD_CMD_REG , LCD_DATA_REG);
0561 led_func_ptr = led_LCD_driver;
0562 led_type = LED_HASLCD;
0563 break;
0564
0565 case DISPLAY_MODEL_LASI:
0566
0567 if (running_on_qemu)
0568 return 1;
0569 LED_DATA_REG = data_reg;
0570 led_func_ptr = led_LASI_driver;
0571 printk(KERN_INFO "LED display at %lx registered\n", LED_DATA_REG);
0572 led_type = LED_NOLCD;
0573 break;
0574
0575 case DISPLAY_MODEL_OLD_ASP:
0576 LED_DATA_REG = data_reg;
0577 led_func_ptr = led_ASP_driver;
0578 printk(KERN_INFO "LED (ASP-style) display at %lx registered\n",
0579 LED_DATA_REG);
0580 led_type = LED_NOLCD;
0581 break;
0582
0583 default:
0584 printk(KERN_ERR "%s: Wrong LCD/LED model %d !\n",
0585 __func__, lcd_info.model);
0586 return 1;
0587 }
0588
0589
0590
0591 initialized++;
0592 register_reboot_notifier(&led_notifier);
0593
0594
0595 if (led_wq) {
0596 queue_delayed_work(led_wq, &led_task, 0);
0597 }
0598
0599 return 0;
0600 }
0601
0602
0603
0604
0605
0606
0607
0608
0609
0610
0611
0612
0613 void __init register_led_regions(void)
0614 {
0615 switch (lcd_info.model) {
0616 case DISPLAY_MODEL_LCD:
0617 request_mem_region((unsigned long)LCD_CMD_REG, 1, "lcd_cmd");
0618 request_mem_region((unsigned long)LCD_DATA_REG, 1, "lcd_data");
0619 break;
0620 case DISPLAY_MODEL_LASI:
0621 case DISPLAY_MODEL_OLD_ASP:
0622 request_mem_region((unsigned long)LED_DATA_REG, 1, "led_data");
0623 break;
0624 }
0625 }
0626
0627
0628
0629
0630
0631
0632
0633
0634
0635
0636
0637 int lcd_print( const char *str )
0638 {
0639 int i;
0640
0641 if (!led_func_ptr || lcd_info.model != DISPLAY_MODEL_LCD)
0642 return 0;
0643
0644
0645 if (led_wq)
0646 cancel_delayed_work_sync(&led_task);
0647
0648
0649 strscpy(lcd_text, str, sizeof(lcd_text));
0650
0651
0652 gsc_writeb(lcd_info.reset_cmd1, LCD_CMD_REG);
0653 udelay(lcd_info.min_cmd_delay);
0654
0655
0656 for (i=0; i < lcd_info.lcd_width; i++) {
0657 if (str && *str)
0658 gsc_writeb(*str++, LCD_DATA_REG);
0659 else
0660 gsc_writeb(' ', LCD_DATA_REG);
0661 udelay(lcd_info.min_cmd_delay);
0662 }
0663
0664
0665 if (led_wq) {
0666 queue_delayed_work(led_wq, &led_task, 0);
0667 }
0668
0669 return lcd_info.lcd_width;
0670 }
0671
0672
0673
0674
0675
0676
0677
0678
0679
0680
0681
0682
0683
0684 int __init led_init(void)
0685 {
0686 struct pdc_chassis_info chassis_info;
0687 int ret;
0688
0689 snprintf(lcd_text_default, sizeof(lcd_text_default),
0690 "Linux %s", init_utsname()->release);
0691
0692
0693 switch (CPU_HVERSION) {
0694 case 0x580:
0695 case 0x581:
0696 case 0x582:
0697 case 0x583:
0698 case 0x58B:
0699 printk(KERN_INFO "%s: KittyHawk-Machine (hversion 0x%x) found, "
0700 "LED detection skipped.\n", __FILE__, CPU_HVERSION);
0701 lcd_no_led_support = 1;
0702 goto found;
0703 }
0704
0705
0706 lcd_info.model = DISPLAY_MODEL_NONE;
0707 chassis_info.actcnt = chassis_info.maxcnt = 0;
0708
0709 ret = pdc_chassis_info(&chassis_info, &lcd_info, sizeof(lcd_info));
0710 if (ret == PDC_OK) {
0711 DPRINTK((KERN_INFO "%s: chassis info: model=%d (%s), "
0712 "lcd_width=%d, cmd_delay=%u,\n"
0713 "%s: sizecnt=%d, actcnt=%ld, maxcnt=%ld\n",
0714 __FILE__, lcd_info.model,
0715 (lcd_info.model==DISPLAY_MODEL_LCD) ? "LCD" :
0716 (lcd_info.model==DISPLAY_MODEL_LASI) ? "LED" : "unknown",
0717 lcd_info.lcd_width, lcd_info.min_cmd_delay,
0718 __FILE__, sizeof(lcd_info),
0719 chassis_info.actcnt, chassis_info.maxcnt));
0720 DPRINTK((KERN_INFO "%s: cmd=%p, data=%p, reset1=%x, reset2=%x, act_enable=%d\n",
0721 __FILE__, lcd_info.lcd_cmd_reg_addr,
0722 lcd_info.lcd_data_reg_addr, lcd_info.reset_cmd1,
0723 lcd_info.reset_cmd2, lcd_info.act_enable ));
0724
0725
0726 if (chassis_info.actcnt <= 0 || chassis_info.actcnt != chassis_info.maxcnt)
0727 goto not_found;
0728
0729 switch (lcd_info.model) {
0730 case DISPLAY_MODEL_LCD:
0731 if (chassis_info.actcnt <
0732 offsetof(struct pdc_chassis_lcd_info_ret_block, _pad)-1)
0733 goto not_found;
0734 if (!lcd_info.act_enable) {
0735 DPRINTK((KERN_INFO "PDC prohibited usage of the LCD.\n"));
0736 goto not_found;
0737 }
0738 break;
0739
0740 case DISPLAY_MODEL_NONE:
0741 printk(KERN_INFO "PDC reported no LCD or LED.\n");
0742 goto not_found;
0743
0744 case DISPLAY_MODEL_LASI:
0745 if (chassis_info.actcnt != 8 && chassis_info.actcnt != 32)
0746 goto not_found;
0747 break;
0748
0749 default:
0750 printk(KERN_WARNING "PDC reported unknown LCD/LED model %d\n",
0751 lcd_info.model);
0752 goto not_found;
0753 }
0754
0755 found:
0756
0757 register_led_driver(lcd_info.model, LCD_CMD_REG, LCD_DATA_REG);
0758 return 0;
0759
0760 } else {
0761 DPRINTK((KERN_INFO "pdc_chassis_info call failed with retval = %d\n", ret));
0762 }
0763
0764 not_found:
0765 lcd_info.model = DISPLAY_MODEL_NONE;
0766 return 1;
0767 }
0768
0769 static void __exit led_exit(void)
0770 {
0771 unregister_reboot_notifier(&led_notifier);
0772 return;
0773 }
0774
0775 #ifdef CONFIG_PROC_FS
0776 module_init(led_create_procfs)
0777 #endif