mirror of
https://github.com/torvalds/linux.git
synced 2024-12-29 14:21:47 +00:00
7d12e780e0
Maintain a per-CPU global "struct pt_regs *" variable which can be used instead of passing regs around manually through all ~1800 interrupt handlers in the Linux kernel. The regs pointer is used in few places, but it potentially costs both stack space and code to pass it around. On the FRV arch, removing the regs parameter from all the genirq function results in a 20% speed up of the IRQ exit path (ie: from leaving timer_interrupt() to leaving do_IRQ()). Where appropriate, an arch may override the generic storage facility and do something different with the variable. On FRV, for instance, the address is maintained in GR28 at all times inside the kernel as part of general exception handling. Having looked over the code, it appears that the parameter may be handed down through up to twenty or so layers of functions. Consider a USB character device attached to a USB hub, attached to a USB controller that posts its interrupts through a cascaded auxiliary interrupt controller. A character device driver may want to pass regs to the sysrq handler through the input layer which adds another few layers of parameter passing. I've build this code with allyesconfig for x86_64 and i386. I've runtested the main part of the code on FRV and i386, though I can't test most of the drivers. I've also done partial conversion for powerpc and MIPS - these at least compile with minimal configurations. This will affect all archs. Mostly the changes should be relatively easy. Take do_IRQ(), store the regs pointer at the beginning, saving the old one: struct pt_regs *old_regs = set_irq_regs(regs); And put the old one back at the end: set_irq_regs(old_regs); Don't pass regs through to generic_handle_irq() or __do_IRQ(). In timer_interrupt(), this sort of change will be necessary: - update_process_times(user_mode(regs)); - profile_tick(CPU_PROFILING, regs); + update_process_times(user_mode(get_irq_regs())); + profile_tick(CPU_PROFILING); I'd like to move update_process_times()'s use of get_irq_regs() into itself, except that i386, alone of the archs, uses something other than user_mode(). Some notes on the interrupt handling in the drivers: (*) input_dev() is now gone entirely. The regs pointer is no longer stored in the input_dev struct. (*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking. It does something different depending on whether it's been supplied with a regs pointer or not. (*) Various IRQ handler function pointers have been moved to type irq_handler_t. Signed-Off-By: David Howells <dhowells@redhat.com> (cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit)
211 lines
9.9 KiB
C
211 lines
9.9 KiB
C
/*******************************************************************
|
|
* This file is part of the Emulex Linux Device Driver for *
|
|
* Fibre Channel Host Bus Adapters. *
|
|
* Copyright (C) 2004-2006 Emulex. All rights reserved. *
|
|
* EMULEX and SLI are trademarks of Emulex. *
|
|
* www.emulex.com *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or *
|
|
* modify it under the terms of version 2 of the GNU General *
|
|
* Public License as published by the Free Software Foundation. *
|
|
* This program is distributed in the hope that it will be useful. *
|
|
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND *
|
|
* WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, *
|
|
* FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT, ARE *
|
|
* DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH DISCLAIMERS ARE HELD *
|
|
* TO BE LEGALLY INVALID. See the GNU General Public License for *
|
|
* more details, a copy of which can be found in the file COPYING *
|
|
* included with this package. *
|
|
*******************************************************************/
|
|
|
|
struct fc_rport;
|
|
void lpfc_dump_mem(struct lpfc_hba *, LPFC_MBOXQ_t *, uint16_t);
|
|
void lpfc_read_nv(struct lpfc_hba *, LPFC_MBOXQ_t *);
|
|
int lpfc_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb,
|
|
struct lpfc_dmabuf *mp);
|
|
void lpfc_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
|
|
void lpfc_config_link(struct lpfc_hba *, LPFC_MBOXQ_t *);
|
|
int lpfc_read_sparam(struct lpfc_hba *, LPFC_MBOXQ_t *);
|
|
void lpfc_read_config(struct lpfc_hba *, LPFC_MBOXQ_t *);
|
|
void lpfc_read_lnk_stat(struct lpfc_hba *, LPFC_MBOXQ_t *);
|
|
int lpfc_reg_login(struct lpfc_hba *, uint32_t, uint8_t *, LPFC_MBOXQ_t *,
|
|
uint32_t);
|
|
void lpfc_unreg_login(struct lpfc_hba *, uint32_t, LPFC_MBOXQ_t *);
|
|
void lpfc_unreg_did(struct lpfc_hba *, uint32_t, LPFC_MBOXQ_t *);
|
|
void lpfc_init_link(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t, uint32_t);
|
|
|
|
|
|
int lpfc_linkdown(struct lpfc_hba *);
|
|
void lpfc_mbx_cmpl_read_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
|
|
|
|
void lpfc_mbx_cmpl_clear_la(struct lpfc_hba *, LPFC_MBOXQ_t *);
|
|
void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
|
|
void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
|
|
void lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
|
|
void lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *, LPFC_MBOXQ_t *);
|
|
int lpfc_nlp_list(struct lpfc_hba *, struct lpfc_nodelist *, int);
|
|
void lpfc_set_disctmo(struct lpfc_hba *);
|
|
int lpfc_can_disctmo(struct lpfc_hba *);
|
|
int lpfc_unreg_rpi(struct lpfc_hba *, struct lpfc_nodelist *);
|
|
int lpfc_check_sli_ndlp(struct lpfc_hba *, struct lpfc_sli_ring *,
|
|
struct lpfc_iocbq *, struct lpfc_nodelist *);
|
|
int lpfc_nlp_remove(struct lpfc_hba *, struct lpfc_nodelist *);
|
|
void lpfc_nlp_init(struct lpfc_hba *, struct lpfc_nodelist *, uint32_t);
|
|
struct lpfc_nodelist *lpfc_setup_disc_node(struct lpfc_hba *, uint32_t);
|
|
void lpfc_disc_list_loopmap(struct lpfc_hba *);
|
|
void lpfc_disc_start(struct lpfc_hba *);
|
|
void lpfc_disc_flush_list(struct lpfc_hba *);
|
|
void lpfc_disc_timeout(unsigned long);
|
|
|
|
struct lpfc_nodelist *lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi);
|
|
|
|
int lpfc_workq_post_event(struct lpfc_hba *, void *, void *, uint32_t);
|
|
int lpfc_do_work(void *);
|
|
int lpfc_disc_state_machine(struct lpfc_hba *, struct lpfc_nodelist *, void *,
|
|
uint32_t);
|
|
|
|
int lpfc_check_sparm(struct lpfc_hba *, struct lpfc_nodelist *,
|
|
struct serv_parm *, uint32_t);
|
|
int lpfc_els_abort(struct lpfc_hba *, struct lpfc_nodelist * ndlp,
|
|
int);
|
|
int lpfc_els_abort_flogi(struct lpfc_hba *);
|
|
int lpfc_initial_flogi(struct lpfc_hba *);
|
|
int lpfc_issue_els_plogi(struct lpfc_hba *, uint32_t, uint8_t);
|
|
int lpfc_issue_els_prli(struct lpfc_hba *, struct lpfc_nodelist *, uint8_t);
|
|
int lpfc_issue_els_adisc(struct lpfc_hba *, struct lpfc_nodelist *, uint8_t);
|
|
int lpfc_issue_els_logo(struct lpfc_hba *, struct lpfc_nodelist *, uint8_t);
|
|
int lpfc_issue_els_scr(struct lpfc_hba *, uint32_t, uint8_t);
|
|
int lpfc_els_free_iocb(struct lpfc_hba *, struct lpfc_iocbq *);
|
|
int lpfc_els_rsp_acc(struct lpfc_hba *, uint32_t, struct lpfc_iocbq *,
|
|
struct lpfc_nodelist *, LPFC_MBOXQ_t *, uint8_t);
|
|
int lpfc_els_rsp_reject(struct lpfc_hba *, uint32_t, struct lpfc_iocbq *,
|
|
struct lpfc_nodelist *);
|
|
int lpfc_els_rsp_adisc_acc(struct lpfc_hba *, struct lpfc_iocbq *,
|
|
struct lpfc_nodelist *);
|
|
int lpfc_els_rsp_prli_acc(struct lpfc_hba *, struct lpfc_iocbq *,
|
|
struct lpfc_nodelist *);
|
|
void lpfc_cancel_retry_delay_tmo(struct lpfc_hba *, struct lpfc_nodelist *);
|
|
void lpfc_els_retry_delay(unsigned long);
|
|
void lpfc_els_retry_delay_handler(struct lpfc_nodelist *);
|
|
void lpfc_els_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
|
|
struct lpfc_iocbq *);
|
|
int lpfc_els_handle_rscn(struct lpfc_hba *);
|
|
int lpfc_els_flush_rscn(struct lpfc_hba *);
|
|
int lpfc_rscn_payload_check(struct lpfc_hba *, uint32_t);
|
|
void lpfc_els_flush_cmd(struct lpfc_hba *);
|
|
int lpfc_els_disc_adisc(struct lpfc_hba *);
|
|
int lpfc_els_disc_plogi(struct lpfc_hba *);
|
|
void lpfc_els_timeout(unsigned long);
|
|
void lpfc_els_timeout_handler(struct lpfc_hba *);
|
|
|
|
void lpfc_ct_unsol_event(struct lpfc_hba *, struct lpfc_sli_ring *,
|
|
struct lpfc_iocbq *);
|
|
int lpfc_ns_cmd(struct lpfc_hba *, struct lpfc_nodelist *, int);
|
|
int lpfc_fdmi_cmd(struct lpfc_hba *, struct lpfc_nodelist *, int);
|
|
void lpfc_fdmi_tmo(unsigned long);
|
|
void lpfc_fdmi_tmo_handler(struct lpfc_hba *);
|
|
|
|
int lpfc_config_port_prep(struct lpfc_hba *);
|
|
int lpfc_config_port_post(struct lpfc_hba *);
|
|
int lpfc_hba_down_prep(struct lpfc_hba *);
|
|
int lpfc_hba_down_post(struct lpfc_hba *);
|
|
void lpfc_hba_init(struct lpfc_hba *, uint32_t *);
|
|
int lpfc_post_buffer(struct lpfc_hba *, struct lpfc_sli_ring *, int, int);
|
|
void lpfc_decode_firmware_rev(struct lpfc_hba *, char *, int);
|
|
int lpfc_online(struct lpfc_hba *);
|
|
int lpfc_offline(struct lpfc_hba *);
|
|
|
|
int lpfc_sli_setup(struct lpfc_hba *);
|
|
int lpfc_sli_queue_setup(struct lpfc_hba *);
|
|
|
|
void lpfc_handle_eratt(struct lpfc_hba *);
|
|
void lpfc_handle_latt(struct lpfc_hba *);
|
|
irqreturn_t lpfc_intr_handler(int, void *);
|
|
|
|
void lpfc_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *);
|
|
void lpfc_config_ring(struct lpfc_hba *, int, LPFC_MBOXQ_t *);
|
|
void lpfc_config_port(struct lpfc_hba *, LPFC_MBOXQ_t *);
|
|
void lpfc_kill_board(struct lpfc_hba *, LPFC_MBOXQ_t *);
|
|
void lpfc_mbox_put(struct lpfc_hba *, LPFC_MBOXQ_t *);
|
|
LPFC_MBOXQ_t *lpfc_mbox_get(struct lpfc_hba *);
|
|
int lpfc_mbox_tmo_val(struct lpfc_hba *, int);
|
|
|
|
int lpfc_mem_alloc(struct lpfc_hba *);
|
|
void lpfc_mem_free(struct lpfc_hba *);
|
|
|
|
void lpfc_poll_timeout(unsigned long ptr);
|
|
void lpfc_poll_start_timer(struct lpfc_hba * phba);
|
|
void lpfc_sli_poll_fcp_ring(struct lpfc_hba * hba);
|
|
struct lpfc_iocbq * lpfc_sli_get_iocbq(struct lpfc_hba *);
|
|
void lpfc_sli_release_iocbq(struct lpfc_hba * phba, struct lpfc_iocbq * iocb);
|
|
uint16_t lpfc_sli_next_iotag(struct lpfc_hba * phba, struct lpfc_iocbq * iocb);
|
|
|
|
void lpfc_reset_barrier(struct lpfc_hba * phba);
|
|
int lpfc_sli_brdready(struct lpfc_hba *, uint32_t);
|
|
int lpfc_sli_brdkill(struct lpfc_hba *);
|
|
int lpfc_sli_brdreset(struct lpfc_hba *);
|
|
int lpfc_sli_brdrestart(struct lpfc_hba *);
|
|
int lpfc_sli_hba_setup(struct lpfc_hba *);
|
|
int lpfc_sli_hba_down(struct lpfc_hba *);
|
|
int lpfc_sli_issue_mbox(struct lpfc_hba *, LPFC_MBOXQ_t *, uint32_t);
|
|
int lpfc_sli_handle_mb_event(struct lpfc_hba *);
|
|
int lpfc_sli_flush_mbox_queue(struct lpfc_hba *);
|
|
int lpfc_sli_handle_slow_ring_event(struct lpfc_hba *,
|
|
struct lpfc_sli_ring *, uint32_t);
|
|
void lpfc_sli_def_mbox_cmpl(struct lpfc_hba *, LPFC_MBOXQ_t *);
|
|
int lpfc_sli_issue_iocb(struct lpfc_hba *, struct lpfc_sli_ring *,
|
|
struct lpfc_iocbq *, uint32_t);
|
|
void lpfc_sli_pcimem_bcopy(void *, void *, uint32_t);
|
|
int lpfc_sli_abort_iocb_ring(struct lpfc_hba *, struct lpfc_sli_ring *);
|
|
int lpfc_sli_ringpostbuf_put(struct lpfc_hba *, struct lpfc_sli_ring *,
|
|
struct lpfc_dmabuf *);
|
|
struct lpfc_dmabuf *lpfc_sli_ringpostbuf_get(struct lpfc_hba *,
|
|
struct lpfc_sli_ring *,
|
|
dma_addr_t);
|
|
int lpfc_sli_issue_abort_iotag32(struct lpfc_hba *, struct lpfc_sli_ring *,
|
|
struct lpfc_iocbq *);
|
|
int lpfc_sli_sum_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t,
|
|
uint64_t, lpfc_ctx_cmd);
|
|
int lpfc_sli_abort_iocb(struct lpfc_hba *, struct lpfc_sli_ring *, uint16_t,
|
|
uint64_t, uint32_t, lpfc_ctx_cmd);
|
|
|
|
void lpfc_mbox_timeout(unsigned long);
|
|
void lpfc_mbox_timeout_handler(struct lpfc_hba *);
|
|
|
|
struct lpfc_nodelist *lpfc_findnode_did(struct lpfc_hba *, uint32_t, uint32_t);
|
|
struct lpfc_nodelist *lpfc_findnode_wwpn(struct lpfc_hba *, uint32_t,
|
|
struct lpfc_name *);
|
|
|
|
int lpfc_sli_issue_mbox_wait(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmboxq,
|
|
uint32_t timeout);
|
|
|
|
int lpfc_sli_issue_iocb_wait(struct lpfc_hba * phba,
|
|
struct lpfc_sli_ring * pring,
|
|
struct lpfc_iocbq * piocb,
|
|
struct lpfc_iocbq * prspiocbq,
|
|
uint32_t timeout);
|
|
void lpfc_sli_abort_fcp_cmpl(struct lpfc_hba * phba,
|
|
struct lpfc_iocbq * cmdiocb,
|
|
struct lpfc_iocbq * rspiocb);
|
|
|
|
void *lpfc_mbuf_alloc(struct lpfc_hba *, int, dma_addr_t *);
|
|
void lpfc_mbuf_free(struct lpfc_hba *, void *, dma_addr_t);
|
|
|
|
/* Function prototypes. */
|
|
const char* lpfc_info(struct Scsi_Host *);
|
|
void lpfc_get_cfgparam(struct lpfc_hba *);
|
|
int lpfc_alloc_sysfs_attr(struct lpfc_hba *);
|
|
void lpfc_free_sysfs_attr(struct lpfc_hba *);
|
|
extern struct class_device_attribute *lpfc_host_attrs[];
|
|
extern struct scsi_host_template lpfc_template;
|
|
extern struct fc_function_template lpfc_transport_functions;
|
|
|
|
void lpfc_get_hba_sym_node_name(struct lpfc_hba * phba, uint8_t * symbp);
|
|
void lpfc_terminate_rport_io(struct fc_rport *);
|
|
void lpfc_dev_loss_tmo_callbk(struct fc_rport *rport);
|
|
|
|
#define ScsiResult(host_code, scsi_code) (((host_code) << 16) | scsi_code)
|
|
#define HBA_EVENT_RSCN 5
|
|
#define HBA_EVENT_LINK_UP 2
|
|
#define HBA_EVENT_LINK_DOWN 3
|