sclp.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 854 行 · 第 1/2 页
C
854 行
sccb_mask_t sclp_send_mask; u32 read_data_function_mask;} __attribute__((packed));static inline void__sclp_notify_state_change(void){ struct list_head *l; struct sclp_register *t; sccb_mask_t receive_mask, send_mask; list_for_each(l, &sclp_reg_list) { t = list_entry(l, struct sclp_register, list); receive_mask = t->receive_mask & sclp_receive_mask; send_mask = t->send_mask & sclp_send_mask; if (t->sclp_receive_mask != receive_mask || t->sclp_send_mask != send_mask) { t->sclp_receive_mask = receive_mask; t->sclp_send_mask = send_mask; if (t->state_change_fn != NULL) t->state_change_fn(t); } }}static voidsclp_state_change(struct evbuf_header *evbuf){ unsigned long flags; struct sclp_statechangebuf *scbuf; spin_lock_irqsave(&sclp_lock, flags); scbuf = (struct sclp_statechangebuf *) evbuf; if (scbuf->validity_sclp_receive_mask) { if (scbuf->mask_length != sizeof(sccb_mask_t)) printk(KERN_WARNING SCLP_CORE_PRINT_HEADER "state change event with mask length %i\n", scbuf->mask_length); else /* set new receive mask */ sclp_receive_mask = scbuf->sclp_receive_mask; } if (scbuf->validity_sclp_send_mask) { if (scbuf->mask_length != sizeof(sccb_mask_t)) printk(KERN_WARNING SCLP_CORE_PRINT_HEADER "state change event with mask length %i\n", scbuf->mask_length); else /* set new send mask */ sclp_send_mask = scbuf->sclp_send_mask; } __sclp_notify_state_change(); spin_unlock_irqrestore(&sclp_lock, flags);}static struct sclp_register sclp_state_change_event = { .receive_mask = EvTyp_StateChange_Mask, .receiver_fn = sclp_state_change};/* * SCLP quiesce event handler */#ifdef CONFIG_SMPstatic voiddo_load_quiesce_psw(void * __unused){ static atomic_t cpuid = ATOMIC_INIT(-1); psw_t quiesce_psw; __u32 status; int i; if (atomic_compare_and_swap(-1, smp_processor_id(), &cpuid)) signal_processor(smp_processor_id(), sigp_stop); /* Wait for all other cpus to enter stopped state */ i = 1; while (i < NR_CPUS) { if (!cpu_online(i)) { i++; continue; } switch (signal_processor_ps(&status, 0, i, sigp_sense)) { case sigp_order_code_accepted: case sigp_status_stored: /* Check for stopped and check stop state */ if (status & 0x50) i++; break; case sigp_busy: break; case sigp_not_operational: i++; break; } } /* Quiesce the last cpu with the special psw */ quiesce_psw.mask = PSW_BASE_BITS | PSW_MASK_WAIT; quiesce_psw.addr = 0xfff; __load_psw(quiesce_psw);}static voiddo_machine_quiesce(void){ on_each_cpu(do_load_quiesce_psw, NULL, 0, 0);}#elsestatic voiddo_machine_quiesce(void){ psw_t quiesce_psw; quiesce_psw.mask = PSW_BASE_BITS | PSW_MASK_WAIT; quiesce_psw.addr = 0xfff; __load_psw(quiesce_psw);}#endifextern void ctrl_alt_del(void);static voidsclp_quiesce(struct evbuf_header *evbuf){ /* * We got a "shutdown" request. * Add a call to an appropriate "shutdown" routine here. This * routine should set all PSWs to 'disabled-wait', 'stopped' * or 'check-stopped' - except 1 PSW which needs to carry a * special bit pattern called 'quiesce PSW'. */ _machine_restart = (void *) do_machine_quiesce; _machine_halt = do_machine_quiesce; _machine_power_off = do_machine_quiesce; ctrl_alt_del();}static struct sclp_register sclp_quiesce_event = { .receive_mask = EvTyp_SigQuiesce_Mask, .receiver_fn = sclp_quiesce};/* initialisation of SCLP */struct init_sccb { struct sccb_header header; u16 _reserved; u16 mask_length; sccb_mask_t receive_mask; sccb_mask_t send_mask; sccb_mask_t sclp_send_mask; sccb_mask_t sclp_receive_mask;} __attribute__((packed));static void sclp_init_mask_retry(unsigned long);static intsclp_init_mask(void){ unsigned long flags; struct init_sccb *sccb; struct sclp_req *req; struct list_head *l; struct sclp_register *t; int rc; sccb = (struct init_sccb *) sclp_init_sccb; /* stick the request structure to the end of the init sccb page */ req = (struct sclp_req *) ((addr_t) sccb + PAGE_SIZE) - 1; /* SCLP setup concerning receiving and sending Event Buffers */ req->command = SCLP_CMDW_WRITEMASK; req->status = SCLP_REQ_QUEUED; req->callback = NULL; req->sccb = sccb; /* setup sccb for writemask command */ memset(sccb, 0, sizeof(struct init_sccb)); sccb->header.length = sizeof(struct init_sccb); sccb->mask_length = sizeof(sccb_mask_t); /* copy in the sccb mask of the registered event types */ spin_lock_irqsave(&sclp_lock, flags); if (!test_bit(SCLP_SHUTDOWN, &sclp_status)) { list_for_each(l, &sclp_reg_list) { t = list_entry(l, struct sclp_register, list); sccb->receive_mask |= t->receive_mask; sccb->send_mask |= t->send_mask; } } sccb->sclp_receive_mask = 0; sccb->sclp_send_mask = 0; if (test_bit(SCLP_INIT, &sclp_status)) { /* add request to sclp queue */ list_add_tail(&req->list, &sclp_req_queue); spin_unlock_irqrestore(&sclp_lock, flags); /* and start if SCLP is idle */ sclp_start_request(); /* now wait for completion */ while (req->status != SCLP_REQ_DONE && req->status != SCLP_REQ_FAILED) sclp_sync_wait(); spin_lock_irqsave(&sclp_lock, flags); } else { /* * Special case for the very first write mask command. * The interrupt handler is not removing request from * the request queue and doesn't call callbacks yet * because there might be an pending old interrupt * after a Re-IPL. We have to receive and ignore it. */ do { rc = __service_call(req->command, req->sccb); if (rc == 0) set_bit(SCLP_RUNNING, &sclp_status); spin_unlock_irqrestore(&sclp_lock, flags); if (rc == -EIO) return -ENOSYS; sclp_sync_wait(); spin_lock_irqsave(&sclp_lock, flags); } while (rc == -EBUSY); } if (sccb->header.response_code != 0x0020) { /* WRITEMASK failed - we cannot rely on receiving a state change event, so initially, polling is the only alternative for us to ever become operational. */ if (!test_bit(SCLP_SHUTDOWN, &sclp_status) && (!timer_pending(&retry_timer) || !mod_timer(&retry_timer, jiffies + SCLP_INIT_POLL_INTERVAL*HZ))) { retry_timer.function = sclp_init_mask_retry; retry_timer.data = 0; retry_timer.expires = jiffies + SCLP_INIT_POLL_INTERVAL*HZ; add_timer(&retry_timer); } } else { sclp_receive_mask = sccb->sclp_receive_mask; sclp_send_mask = sccb->sclp_send_mask; __sclp_notify_state_change(); } spin_unlock_irqrestore(&sclp_lock, flags); return 0;}static voidsclp_init_mask_retry(unsigned long data) { sclp_init_mask();}/* Reboot event handler - reset send and receive mask to prevent pending SCLP * events from interfering with rebooted system. */static intsclp_reboot_event(struct notifier_block *this, unsigned long event, void *ptr){ unsigned long flags; /* Note: need spinlock to maintain atomicity when accessing global * variables. */ spin_lock_irqsave(&sclp_lock, flags); set_bit(SCLP_SHUTDOWN, &sclp_status); spin_unlock_irqrestore(&sclp_lock, flags); sclp_init_mask(); return NOTIFY_DONE;}static struct notifier_block sclp_reboot_notifier = { .notifier_call = sclp_reboot_event};/* * sclp setup function. Called early (no kmalloc!) from sclp_console_init(). */static intsclp_init(void){ int rc; if (test_bit(SCLP_INIT, &sclp_status)) /* Already initialized. */ return 0; spin_lock_init(&sclp_lock); INIT_LIST_HEAD(&sclp_req_queue); /* init event list */ INIT_LIST_HEAD(&sclp_reg_list); list_add(&sclp_state_change_event.list, &sclp_reg_list); list_add(&sclp_quiesce_event.list, &sclp_reg_list); rc = register_reboot_notifier(&sclp_reboot_notifier); if (rc) return rc; /* * request the 0x2401 external interrupt * The sclp driver is initialized early (before kmalloc works). We * need to use register_early_external_interrupt. */ if (register_early_external_interrupt(0x2401, sclp_interrupt_handler, &ext_int_info_hwc) != 0) return -EBUSY; /* enable service-signal external interruptions, * Control Register 0 bit 22 := 1 * (besides PSW bit 7 must be set to 1 sometimes for external * interruptions) */ ctl_set_bit(0, 9); init_timer(&retry_timer); init_timer(&sclp_busy_timer); /* do the initial write event mask */ rc = sclp_init_mask(); if (rc == 0) { /* Ok, now everything is setup right. */ set_bit(SCLP_INIT, &sclp_status); return 0; } /* The sclp_init_mask failed. SCLP is broken, unregister and exit. */ ctl_clear_bit(0,9); unregister_early_external_interrupt(0x2401, sclp_interrupt_handler, &ext_int_info_hwc); return rc;}/* * Register the SCLP event listener identified by REG. Return 0 on success. * Some error codes and their meaning: * * -ENODEV = SCLP interface is not supported on this machine * -EBUSY = there is already a listener registered for the requested * event type * -EIO = SCLP interface is currently not operational */intsclp_register(struct sclp_register *reg){ unsigned long flags; struct list_head *l; struct sclp_register *t; if (!MACHINE_HAS_SCLP) return -ENODEV; if (!test_bit(SCLP_INIT, &sclp_status)) sclp_init(); spin_lock_irqsave(&sclp_lock, flags); /* check already registered event masks for collisions */ list_for_each(l, &sclp_reg_list) { t = list_entry(l, struct sclp_register, list); if (t->receive_mask & reg->receive_mask || t->send_mask & reg->send_mask) { spin_unlock_irqrestore(&sclp_lock, flags); return -EBUSY; } } /* * set present mask to 0 to trigger state change * callback in sclp_init_mask */ reg->sclp_receive_mask = 0; reg->sclp_send_mask = 0; list_add(®->list, &sclp_reg_list); spin_unlock_irqrestore(&sclp_lock, flags); sclp_init_mask(); return 0;}/* * Unregister the SCLP event listener identified by REG. */voidsclp_unregister(struct sclp_register *reg){ unsigned long flags; spin_lock_irqsave(&sclp_lock, flags); list_del(®->list); spin_unlock_irqrestore(&sclp_lock, flags); sclp_init_mask();}#define SCLP_EVBUF_PROCESSED 0x80/* * Traverse array of event buffers contained in SCCB and remove all buffers * with a set "processed" flag. Return the number of unprocessed buffers. */intsclp_remove_processed(struct sccb_header *sccb){ struct evbuf_header *evbuf; int unprocessed; u16 remaining; evbuf = (struct evbuf_header *) (sccb + 1); unprocessed = 0; remaining = sccb->length - sizeof(struct sccb_header); while (remaining > 0) { remaining -= evbuf->length; if (evbuf->flags & SCLP_EVBUF_PROCESSED) { sccb->length -= evbuf->length; memcpy((void *) evbuf, (void *) ((addr_t) evbuf + evbuf->length), remaining); } else { unprocessed++; evbuf = (struct evbuf_header *) ((addr_t) evbuf + evbuf->length); } } return unprocessed;}module_init(sclp_init);EXPORT_SYMBOL(sclp_add_request);EXPORT_SYMBOL(sclp_sync_wait);EXPORT_SYMBOL(sclp_register);EXPORT_SYMBOL(sclp_unregister);EXPORT_SYMBOL(sclp_error_message);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?