📄 mf.c
字号:
}/* * The primary partition VSP object is acknowledging the receipt * of a flow we sent to them. If there are other flows queued * up, we must send another one now... */static void handle_ack(struct io_mf_lp_event *event){ unsigned long flags; struct pending_event *two = NULL; unsigned long free_it = 0; struct ce_msg_data *ce_msg_data; struct ce_msg_data *pce_msg_data; struct vsp_rsp_data *rsp; /* handle current event */ if (pending_event_head == NULL) { printk(KERN_ERR "mf.c: stack empty for receiving ack\n"); return; } switch (event->hp_lp_event.xSubtype) { case 0: /* CE msg */ ce_msg_data = &event->data.ce_msg; if (ce_msg_data->ce_msg[3] != 0x40) { free_it = 1; break; } if (ce_msg_data->ce_msg[2] == 0) break; free_it = 1; pce_msg_data = &pending_event_head->event.data.ce_msg; if (pce_msg_data->completion != NULL) { ce_msg_comp_hdlr handler = pce_msg_data->completion->handler; void *token = pce_msg_data->completion->token; if (handler != NULL) (*handler)(token, ce_msg_data); } break; case 4: /* allocate */ case 5: /* deallocate */ if (pending_event_head->hdlr != NULL) (*pending_event_head->hdlr)((void *)event->hp_lp_event.xCorrelationToken, event->data.alloc.count); free_it = 1; break; case 6: free_it = 1; rsp = (struct vsp_rsp_data *)event->data.vsp_cmd.token; if (rsp == NULL) { printk(KERN_ERR "mf.c: no rsp\n"); break; } if (rsp->response != NULL) memcpy(rsp->response, &event->data.vsp_cmd, sizeof(event->data.vsp_cmd)); complete(&rsp->com); break; } /* remove from queue */ spin_lock_irqsave(&pending_event_spinlock, flags); if ((pending_event_head != NULL) && (free_it == 1)) { struct pending_event *oldHead = pending_event_head; pending_event_head = pending_event_head->next; two = pending_event_head; free_pending_event(oldHead); } spin_unlock_irqrestore(&pending_event_spinlock, flags); /* send next waiting event */ if (two != NULL) signal_event(NULL);}/* * This is the generic event handler we are registering with * the Hypervisor. Ensure the flows are for us, and then * parse it enough to know if it is an interrupt or an * acknowledge. */static void hv_handler(struct HvLpEvent *event, struct pt_regs *regs){ if ((event != NULL) && (event->xType == HvLpEvent_Type_MachineFac)) { switch(event->xFlags.xFunction) { case HvLpEvent_Function_Ack: handle_ack((struct io_mf_lp_event *)event); break; case HvLpEvent_Function_Int: handle_int((struct io_mf_lp_event *)event); break; default: printk(KERN_ERR "mf.c: non ack/int event received\n"); break; } } else printk(KERN_ERR "mf.c: alien event received\n");}/* * Global kernel interface to allocate and seed events into the * Hypervisor. */void mf_allocate_lp_events(HvLpIndex target_lp, HvLpEvent_Type type, unsigned size, unsigned count, MFCompleteHandler hdlr, void *user_token){ struct pending_event *ev = new_pending_event(); int rc; if (ev == NULL) { rc = -ENOMEM; } else { ev->event.hp_lp_event.xSubtype = 4; ev->event.hp_lp_event.xCorrelationToken = (u64)user_token; ev->event.hp_lp_event.x.xSubtypeData = subtype_data('M', 'F', 'M', 'A'); ev->event.data.alloc.target_lp = target_lp; ev->event.data.alloc.type = type; ev->event.data.alloc.size = size; ev->event.data.alloc.count = count; ev->hdlr = hdlr; rc = signal_event(ev); } if ((rc != 0) && (hdlr != NULL)) (*hdlr)(user_token, rc);}EXPORT_SYMBOL(mf_allocate_lp_events);/* * Global kernel interface to unseed and deallocate events already in * Hypervisor. */void mf_deallocate_lp_events(HvLpIndex target_lp, HvLpEvent_Type type, unsigned count, MFCompleteHandler hdlr, void *user_token){ struct pending_event *ev = new_pending_event(); int rc; if (ev == NULL) rc = -ENOMEM; else { ev->event.hp_lp_event.xSubtype = 5; ev->event.hp_lp_event.xCorrelationToken = (u64)user_token; ev->event.hp_lp_event.x.xSubtypeData = subtype_data('M', 'F', 'M', 'D'); ev->event.data.alloc.target_lp = target_lp; ev->event.data.alloc.type = type; ev->event.data.alloc.count = count; ev->hdlr = hdlr; rc = signal_event(ev); } if ((rc != 0) && (hdlr != NULL)) (*hdlr)(user_token, rc);}EXPORT_SYMBOL(mf_deallocate_lp_events);/* * Global kernel interface to tell the VSP object in the primary * partition to power this partition off. */void mf_power_off(void){ printk(KERN_INFO "mf.c: Down it goes...\n"); signal_ce_msg_simple(0x4d, NULL); for (;;) ;}/* * Global kernel interface to tell the VSP object in the primary * partition to reboot this partition. */void mf_reboot(void){ printk(KERN_INFO "mf.c: Preparing to bounce...\n"); signal_ce_msg_simple(0x4e, NULL); for (;;) ;}/* * Display a single word SRC onto the VSP control panel. */void mf_display_src(u32 word){ u8 ce[12]; memset(ce, 0, sizeof(ce)); ce[3] = 0x4a; ce[7] = 0x01; ce[8] = word >> 24; ce[9] = word >> 16; ce[10] = word >> 8; ce[11] = word; signal_ce_msg(ce, NULL);}/* * Display a single word SRC of the form "PROGXXXX" on the VSP control panel. */void mf_display_progress(u16 value){ u8 ce[12]; u8 src[72]; memcpy(ce, "\x00\x00\x04\x4A\x00\x00\x00\x48\x00\x00\x00\x00", 12); memcpy(src, "\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00PROGxxxx ", 72); src[6] = value >> 8; src[7] = value & 255; src[44] = "0123456789ABCDEF"[(value >> 12) & 15]; src[45] = "0123456789ABCDEF"[(value >> 8) & 15]; src[46] = "0123456789ABCDEF"[(value >> 4) & 15]; src[47] = "0123456789ABCDEF"[value & 15]; dma_and_signal_ce_msg(ce, NULL, src, sizeof(src), 9 * 64 * 1024);}/* * Clear the VSP control panel. Used to "erase" an SRC that was * previously displayed. */void mf_clear_src(void){ signal_ce_msg_simple(0x4b, NULL);}/* * Initialization code here. */void mf_init(void){ int i; /* initialize */ spin_lock_init(&pending_event_spinlock); for (i = 0; i < sizeof(pending_event_prealloc) / sizeof(*pending_event_prealloc); ++i) free_pending_event(&pending_event_prealloc[i]); HvLpEvent_registerHandler(HvLpEvent_Type_MachineFac, &hv_handler); /* virtual continue ack */ signal_ce_msg_simple(0x57, NULL); /* initialization complete */ printk(KERN_NOTICE "mf.c: iSeries Linux LPAR Machine Facilities " "initialized\n");}struct rtc_time_data { struct completion com; struct ce_msg_data ce_msg; int rc;};static void get_rtc_time_complete(void *token, struct ce_msg_data *ce_msg){ struct rtc_time_data *rtc = token; memcpy(&rtc->ce_msg, ce_msg, sizeof(rtc->ce_msg)); rtc->rc = 0; complete(&rtc->com);}static int rtc_set_tm(int rc, u8 *ce_msg, struct rtc_time *tm){ tm->tm_wday = 0; tm->tm_yday = 0; tm->tm_isdst = 0; if (rc) { tm->tm_sec = 0; tm->tm_min = 0; tm->tm_hour = 0; tm->tm_mday = 15; tm->tm_mon = 5; tm->tm_year = 52; return rc; } if ((ce_msg[2] == 0xa9) || (ce_msg[2] == 0xaf)) { /* TOD clock is not set */ tm->tm_sec = 1; tm->tm_min = 1; tm->tm_hour = 1; tm->tm_mday = 10; tm->tm_mon = 8; tm->tm_year = 71; mf_set_rtc(tm); } { u8 year = ce_msg[5]; u8 sec = ce_msg[6]; u8 min = ce_msg[7]; u8 hour = ce_msg[8]; u8 day = ce_msg[10]; u8 mon = ce_msg[11]; BCD_TO_BIN(sec); BCD_TO_BIN(min); BCD_TO_BIN(hour); BCD_TO_BIN(day); BCD_TO_BIN(mon); BCD_TO_BIN(year); if (year <= 69) year += 100; tm->tm_sec = sec; tm->tm_min = min; tm->tm_hour = hour; tm->tm_mday = day; tm->tm_mon = mon; tm->tm_year = year; } return 0;}int mf_get_rtc(struct rtc_time *tm){ struct ce_msg_comp_data ce_complete; struct rtc_time_data rtc_data; int rc; memset(&ce_complete, 0, sizeof(ce_complete)); memset(&rtc_data, 0, sizeof(rtc_data)); init_completion(&rtc_data.com); ce_complete.handler = &get_rtc_time_complete; ce_complete.token = &rtc_data; rc = signal_ce_msg_simple(0x40, &ce_complete); if (rc) return rc; wait_for_completion(&rtc_data.com); return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm);}struct boot_rtc_time_data { int busy; struct ce_msg_data ce_msg; int rc;};static void get_boot_rtc_time_complete(void *token, struct ce_msg_data *ce_msg){ struct boot_rtc_time_data *rtc = token; memcpy(&rtc->ce_msg, ce_msg, sizeof(rtc->ce_msg)); rtc->rc = 0; rtc->busy = 0;}int mf_get_boot_rtc(struct rtc_time *tm){ struct ce_msg_comp_data ce_complete; struct boot_rtc_time_data rtc_data; int rc; memset(&ce_complete, 0, sizeof(ce_complete)); memset(&rtc_data, 0, sizeof(rtc_data)); rtc_data.busy = 1; ce_complete.handler = &get_boot_rtc_time_complete; ce_complete.token = &rtc_data; rc = signal_ce_msg_simple(0x40, &ce_complete); if (rc) return rc; /* We need to poll here as we are not yet taking interrupts */ while (rtc_data.busy) { if (hvlpevent_is_pending()) process_hvlpevents(NULL); } return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm);}int mf_set_rtc(struct rtc_time *tm){ char ce_time[12]; u8 day, mon, hour, min, sec, y1, y2; unsigned year; year = 1900 + tm->tm_year; y1 = year / 100; y2 = year % 100; sec = tm->tm_sec; min = tm->tm_min; hour = tm->tm_hour; day = tm->tm_mday; mon = tm->tm_mon + 1; BIN_TO_BCD(sec); BIN_TO_BCD(min); BIN_TO_BCD(hour); BIN_TO_BCD(mon); BIN_TO_BCD(day); BIN_TO_BCD(y1); BIN_TO_BCD(y2); memset(ce_time, 0, sizeof(ce_time)); ce_time[3] = 0x41; ce_time[4] = y1; ce_time[5] = y2; ce_time[6] = sec; ce_time[7] = min; ce_time[8] = hour; ce_time[10] = day; ce_time[11] = mon; return signal_ce_msg(ce_time, NULL);}#ifdef CONFIG_PROC_FSstatic int proc_mf_dump_cmdline(char *page, char **start, off_t off, int count, int *eof, void *data){ int len; char *p; struct vsp_cmd_data vsp_cmd; int rc; dma_addr_t dma_addr;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -