162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright IBM Corp. 2006, 2023 462306a36Sopenharmony_ci * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> 562306a36Sopenharmony_ci * Martin Schwidefsky <schwidefsky@de.ibm.com> 662306a36Sopenharmony_ci * Ralph Wuerthner <rwuerthn@de.ibm.com> 762306a36Sopenharmony_ci * Felix Beck <felix.beck@de.ibm.com> 862306a36Sopenharmony_ci * Holger Dengler <hd@linux.vnet.ibm.com> 962306a36Sopenharmony_ci * Harald Freudenberger <freude@linux.ibm.com> 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Adjunct processor bus. 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define KMSG_COMPONENT "ap" 1562306a36Sopenharmony_ci#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/kernel_stat.h> 1862306a36Sopenharmony_ci#include <linux/moduleparam.h> 1962306a36Sopenharmony_ci#include <linux/init.h> 2062306a36Sopenharmony_ci#include <linux/delay.h> 2162306a36Sopenharmony_ci#include <linux/err.h> 2262306a36Sopenharmony_ci#include <linux/freezer.h> 2362306a36Sopenharmony_ci#include <linux/interrupt.h> 2462306a36Sopenharmony_ci#include <linux/workqueue.h> 2562306a36Sopenharmony_ci#include <linux/slab.h> 2662306a36Sopenharmony_ci#include <linux/notifier.h> 2762306a36Sopenharmony_ci#include <linux/kthread.h> 2862306a36Sopenharmony_ci#include <linux/mutex.h> 2962306a36Sopenharmony_ci#include <asm/airq.h> 3062306a36Sopenharmony_ci#include <asm/tpi.h> 3162306a36Sopenharmony_ci#include <linux/atomic.h> 3262306a36Sopenharmony_ci#include <asm/isc.h> 3362306a36Sopenharmony_ci#include <linux/hrtimer.h> 3462306a36Sopenharmony_ci#include <linux/ktime.h> 3562306a36Sopenharmony_ci#include <asm/facility.h> 3662306a36Sopenharmony_ci#include <linux/crypto.h> 3762306a36Sopenharmony_ci#include <linux/mod_devicetable.h> 3862306a36Sopenharmony_ci#include <linux/debugfs.h> 3962306a36Sopenharmony_ci#include <linux/ctype.h> 4062306a36Sopenharmony_ci#include <linux/module.h> 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#include "ap_bus.h" 4362306a36Sopenharmony_ci#include "ap_debug.h" 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* 4662306a36Sopenharmony_ci * Module parameters; note though this file itself isn't modular. 4762306a36Sopenharmony_ci */ 4862306a36Sopenharmony_ciint ap_domain_index = -1; /* Adjunct Processor Domain Index */ 4962306a36Sopenharmony_cistatic DEFINE_SPINLOCK(ap_domain_lock); 5062306a36Sopenharmony_cimodule_param_named(domain, ap_domain_index, int, 0440); 5162306a36Sopenharmony_ciMODULE_PARM_DESC(domain, "domain index for ap devices"); 5262306a36Sopenharmony_ciEXPORT_SYMBOL(ap_domain_index); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic int ap_thread_flag; 5562306a36Sopenharmony_cimodule_param_named(poll_thread, ap_thread_flag, int, 0440); 5662306a36Sopenharmony_ciMODULE_PARM_DESC(poll_thread, "Turn on/off poll thread, default is 0 (off)."); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic char *apm_str; 5962306a36Sopenharmony_cimodule_param_named(apmask, apm_str, charp, 0440); 6062306a36Sopenharmony_ciMODULE_PARM_DESC(apmask, "AP bus adapter mask."); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic char *aqm_str; 6362306a36Sopenharmony_cimodule_param_named(aqmask, aqm_str, charp, 0440); 6462306a36Sopenharmony_ciMODULE_PARM_DESC(aqmask, "AP bus domain mask."); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic int ap_useirq = 1; 6762306a36Sopenharmony_cimodule_param_named(useirq, ap_useirq, int, 0440); 6862306a36Sopenharmony_ciMODULE_PARM_DESC(useirq, "Use interrupt if available, default is 1 (on)."); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ciatomic_t ap_max_msg_size = ATOMIC_INIT(AP_DEFAULT_MAX_MSG_SIZE); 7162306a36Sopenharmony_ciEXPORT_SYMBOL(ap_max_msg_size); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic struct device *ap_root_device; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci/* Hashtable of all queue devices on the AP bus */ 7662306a36Sopenharmony_ciDEFINE_HASHTABLE(ap_queues, 8); 7762306a36Sopenharmony_ci/* lock used for the ap_queues hashtable */ 7862306a36Sopenharmony_ciDEFINE_SPINLOCK(ap_queues_lock); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci/* Default permissions (ioctl, card and domain masking) */ 8162306a36Sopenharmony_cistruct ap_perms ap_perms; 8262306a36Sopenharmony_ciEXPORT_SYMBOL(ap_perms); 8362306a36Sopenharmony_ciDEFINE_MUTEX(ap_perms_mutex); 8462306a36Sopenharmony_ciEXPORT_SYMBOL(ap_perms_mutex); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci/* # of bus scans since init */ 8762306a36Sopenharmony_cistatic atomic64_t ap_scan_bus_count; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/* # of bindings complete since init */ 9062306a36Sopenharmony_cistatic atomic64_t ap_bindings_complete_count = ATOMIC64_INIT(0); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci/* completion for initial APQN bindings complete */ 9362306a36Sopenharmony_cistatic DECLARE_COMPLETION(ap_init_apqn_bindings_complete); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic struct ap_config_info *ap_qci_info; 9662306a36Sopenharmony_cistatic struct ap_config_info *ap_qci_info_old; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci/* 9962306a36Sopenharmony_ci * AP bus related debug feature things. 10062306a36Sopenharmony_ci */ 10162306a36Sopenharmony_cidebug_info_t *ap_dbf_info; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci/* 10462306a36Sopenharmony_ci * Workqueue timer for bus rescan. 10562306a36Sopenharmony_ci */ 10662306a36Sopenharmony_cistatic struct timer_list ap_config_timer; 10762306a36Sopenharmony_cistatic int ap_config_time = AP_CONFIG_TIME; 10862306a36Sopenharmony_cistatic void ap_scan_bus(struct work_struct *); 10962306a36Sopenharmony_cistatic DECLARE_WORK(ap_scan_work, ap_scan_bus); 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci/* 11262306a36Sopenharmony_ci * Tasklet & timer for AP request polling and interrupts 11362306a36Sopenharmony_ci */ 11462306a36Sopenharmony_cistatic void ap_tasklet_fn(unsigned long); 11562306a36Sopenharmony_cistatic DECLARE_TASKLET_OLD(ap_tasklet, ap_tasklet_fn); 11662306a36Sopenharmony_cistatic DECLARE_WAIT_QUEUE_HEAD(ap_poll_wait); 11762306a36Sopenharmony_cistatic struct task_struct *ap_poll_kthread; 11862306a36Sopenharmony_cistatic DEFINE_MUTEX(ap_poll_thread_mutex); 11962306a36Sopenharmony_cistatic DEFINE_SPINLOCK(ap_poll_timer_lock); 12062306a36Sopenharmony_cistatic struct hrtimer ap_poll_timer; 12162306a36Sopenharmony_ci/* 12262306a36Sopenharmony_ci * In LPAR poll with 4kHz frequency. Poll every 250000 nanoseconds. 12362306a36Sopenharmony_ci * If z/VM change to 1500000 nanoseconds to adjust to z/VM polling. 12462306a36Sopenharmony_ci */ 12562306a36Sopenharmony_cistatic unsigned long poll_high_timeout = 250000UL; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci/* 12862306a36Sopenharmony_ci * Some state machine states only require a low frequency polling. 12962306a36Sopenharmony_ci * We use 25 Hz frequency for these. 13062306a36Sopenharmony_ci */ 13162306a36Sopenharmony_cistatic unsigned long poll_low_timeout = 40000000UL; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci/* Maximum domain id, if not given via qci */ 13462306a36Sopenharmony_cistatic int ap_max_domain_id = 15; 13562306a36Sopenharmony_ci/* Maximum adapter id, if not given via qci */ 13662306a36Sopenharmony_cistatic int ap_max_adapter_id = 63; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic struct bus_type ap_bus_type; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci/* Adapter interrupt definitions */ 14162306a36Sopenharmony_cistatic void ap_interrupt_handler(struct airq_struct *airq, 14262306a36Sopenharmony_ci struct tpi_info *tpi_info); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistatic bool ap_irq_flag; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic struct airq_struct ap_airq = { 14762306a36Sopenharmony_ci .handler = ap_interrupt_handler, 14862306a36Sopenharmony_ci .isc = AP_ISC, 14962306a36Sopenharmony_ci}; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci/** 15262306a36Sopenharmony_ci * ap_airq_ptr() - Get the address of the adapter interrupt indicator 15362306a36Sopenharmony_ci * 15462306a36Sopenharmony_ci * Returns the address of the local-summary-indicator of the adapter 15562306a36Sopenharmony_ci * interrupt handler for AP, or NULL if adapter interrupts are not 15662306a36Sopenharmony_ci * available. 15762306a36Sopenharmony_ci */ 15862306a36Sopenharmony_civoid *ap_airq_ptr(void) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci if (ap_irq_flag) 16162306a36Sopenharmony_ci return ap_airq.lsi_ptr; 16262306a36Sopenharmony_ci return NULL; 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci/** 16662306a36Sopenharmony_ci * ap_interrupts_available(): Test if AP interrupts are available. 16762306a36Sopenharmony_ci * 16862306a36Sopenharmony_ci * Returns 1 if AP interrupts are available. 16962306a36Sopenharmony_ci */ 17062306a36Sopenharmony_cistatic int ap_interrupts_available(void) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci return test_facility(65); 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci/** 17662306a36Sopenharmony_ci * ap_qci_available(): Test if AP configuration 17762306a36Sopenharmony_ci * information can be queried via QCI subfunction. 17862306a36Sopenharmony_ci * 17962306a36Sopenharmony_ci * Returns 1 if subfunction PQAP(QCI) is available. 18062306a36Sopenharmony_ci */ 18162306a36Sopenharmony_cistatic int ap_qci_available(void) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci return test_facility(12); 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci/** 18762306a36Sopenharmony_ci * ap_apft_available(): Test if AP facilities test (APFT) 18862306a36Sopenharmony_ci * facility is available. 18962306a36Sopenharmony_ci * 19062306a36Sopenharmony_ci * Returns 1 if APFT is available. 19162306a36Sopenharmony_ci */ 19262306a36Sopenharmony_cistatic int ap_apft_available(void) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci return test_facility(15); 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci/* 19862306a36Sopenharmony_ci * ap_qact_available(): Test if the PQAP(QACT) subfunction is available. 19962306a36Sopenharmony_ci * 20062306a36Sopenharmony_ci * Returns 1 if the QACT subfunction is available. 20162306a36Sopenharmony_ci */ 20262306a36Sopenharmony_cistatic inline int ap_qact_available(void) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci if (ap_qci_info) 20562306a36Sopenharmony_ci return ap_qci_info->qact; 20662306a36Sopenharmony_ci return 0; 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci/* 21062306a36Sopenharmony_ci * ap_sb_available(): Test if the AP secure binding facility is available. 21162306a36Sopenharmony_ci * 21262306a36Sopenharmony_ci * Returns 1 if secure binding facility is available. 21362306a36Sopenharmony_ci */ 21462306a36Sopenharmony_ciint ap_sb_available(void) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci if (ap_qci_info) 21762306a36Sopenharmony_ci return ap_qci_info->apsb; 21862306a36Sopenharmony_ci return 0; 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci/* 22262306a36Sopenharmony_ci * ap_is_se_guest(): Check for SE guest with AP pass-through support. 22362306a36Sopenharmony_ci */ 22462306a36Sopenharmony_cibool ap_is_se_guest(void) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci return is_prot_virt_guest() && ap_sb_available(); 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ciEXPORT_SYMBOL(ap_is_se_guest); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci/* 23162306a36Sopenharmony_ci * ap_fetch_qci_info(): Fetch cryptographic config info 23262306a36Sopenharmony_ci * 23362306a36Sopenharmony_ci * Returns the ap configuration info fetched via PQAP(QCI). 23462306a36Sopenharmony_ci * On success 0 is returned, on failure a negative errno 23562306a36Sopenharmony_ci * is returned, e.g. if the PQAP(QCI) instruction is not 23662306a36Sopenharmony_ci * available, the return value will be -EOPNOTSUPP. 23762306a36Sopenharmony_ci */ 23862306a36Sopenharmony_cistatic inline int ap_fetch_qci_info(struct ap_config_info *info) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci if (!ap_qci_available()) 24162306a36Sopenharmony_ci return -EOPNOTSUPP; 24262306a36Sopenharmony_ci if (!info) 24362306a36Sopenharmony_ci return -EINVAL; 24462306a36Sopenharmony_ci return ap_qci(info); 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci/** 24862306a36Sopenharmony_ci * ap_init_qci_info(): Allocate and query qci config info. 24962306a36Sopenharmony_ci * Does also update the static variables ap_max_domain_id 25062306a36Sopenharmony_ci * and ap_max_adapter_id if this info is available. 25162306a36Sopenharmony_ci */ 25262306a36Sopenharmony_cistatic void __init ap_init_qci_info(void) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci if (!ap_qci_available()) { 25562306a36Sopenharmony_ci AP_DBF_INFO("%s QCI not supported\n", __func__); 25662306a36Sopenharmony_ci return; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci ap_qci_info = kzalloc(sizeof(*ap_qci_info), GFP_KERNEL); 26062306a36Sopenharmony_ci if (!ap_qci_info) 26162306a36Sopenharmony_ci return; 26262306a36Sopenharmony_ci ap_qci_info_old = kzalloc(sizeof(*ap_qci_info_old), GFP_KERNEL); 26362306a36Sopenharmony_ci if (!ap_qci_info_old) { 26462306a36Sopenharmony_ci kfree(ap_qci_info); 26562306a36Sopenharmony_ci ap_qci_info = NULL; 26662306a36Sopenharmony_ci return; 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci if (ap_fetch_qci_info(ap_qci_info) != 0) { 26962306a36Sopenharmony_ci kfree(ap_qci_info); 27062306a36Sopenharmony_ci kfree(ap_qci_info_old); 27162306a36Sopenharmony_ci ap_qci_info = NULL; 27262306a36Sopenharmony_ci ap_qci_info_old = NULL; 27362306a36Sopenharmony_ci return; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci AP_DBF_INFO("%s successful fetched initial qci info\n", __func__); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci if (ap_qci_info->apxa) { 27862306a36Sopenharmony_ci if (ap_qci_info->na) { 27962306a36Sopenharmony_ci ap_max_adapter_id = ap_qci_info->na; 28062306a36Sopenharmony_ci AP_DBF_INFO("%s new ap_max_adapter_id is %d\n", 28162306a36Sopenharmony_ci __func__, ap_max_adapter_id); 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci if (ap_qci_info->nd) { 28462306a36Sopenharmony_ci ap_max_domain_id = ap_qci_info->nd; 28562306a36Sopenharmony_ci AP_DBF_INFO("%s new ap_max_domain_id is %d\n", 28662306a36Sopenharmony_ci __func__, ap_max_domain_id); 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci memcpy(ap_qci_info_old, ap_qci_info, sizeof(*ap_qci_info)); 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci/* 29462306a36Sopenharmony_ci * ap_test_config(): helper function to extract the nrth bit 29562306a36Sopenharmony_ci * within the unsigned int array field. 29662306a36Sopenharmony_ci */ 29762306a36Sopenharmony_cistatic inline int ap_test_config(unsigned int *field, unsigned int nr) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci return ap_test_bit((field + (nr >> 5)), (nr & 0x1f)); 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci/* 30362306a36Sopenharmony_ci * ap_test_config_card_id(): Test, whether an AP card ID is configured. 30462306a36Sopenharmony_ci * 30562306a36Sopenharmony_ci * Returns 0 if the card is not configured 30662306a36Sopenharmony_ci * 1 if the card is configured or 30762306a36Sopenharmony_ci * if the configuration information is not available 30862306a36Sopenharmony_ci */ 30962306a36Sopenharmony_cistatic inline int ap_test_config_card_id(unsigned int id) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci if (id > ap_max_adapter_id) 31262306a36Sopenharmony_ci return 0; 31362306a36Sopenharmony_ci if (ap_qci_info) 31462306a36Sopenharmony_ci return ap_test_config(ap_qci_info->apm, id); 31562306a36Sopenharmony_ci return 1; 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci/* 31962306a36Sopenharmony_ci * ap_test_config_usage_domain(): Test, whether an AP usage domain 32062306a36Sopenharmony_ci * is configured. 32162306a36Sopenharmony_ci * 32262306a36Sopenharmony_ci * Returns 0 if the usage domain is not configured 32362306a36Sopenharmony_ci * 1 if the usage domain is configured or 32462306a36Sopenharmony_ci * if the configuration information is not available 32562306a36Sopenharmony_ci */ 32662306a36Sopenharmony_ciint ap_test_config_usage_domain(unsigned int domain) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci if (domain > ap_max_domain_id) 32962306a36Sopenharmony_ci return 0; 33062306a36Sopenharmony_ci if (ap_qci_info) 33162306a36Sopenharmony_ci return ap_test_config(ap_qci_info->aqm, domain); 33262306a36Sopenharmony_ci return 1; 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ciEXPORT_SYMBOL(ap_test_config_usage_domain); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci/* 33762306a36Sopenharmony_ci * ap_test_config_ctrl_domain(): Test, whether an AP control domain 33862306a36Sopenharmony_ci * is configured. 33962306a36Sopenharmony_ci * @domain AP control domain ID 34062306a36Sopenharmony_ci * 34162306a36Sopenharmony_ci * Returns 1 if the control domain is configured 34262306a36Sopenharmony_ci * 0 in all other cases 34362306a36Sopenharmony_ci */ 34462306a36Sopenharmony_ciint ap_test_config_ctrl_domain(unsigned int domain) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci if (!ap_qci_info || domain > ap_max_domain_id) 34762306a36Sopenharmony_ci return 0; 34862306a36Sopenharmony_ci return ap_test_config(ap_qci_info->adm, domain); 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ciEXPORT_SYMBOL(ap_test_config_ctrl_domain); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci/* 35362306a36Sopenharmony_ci * ap_queue_info(): Check and get AP queue info. 35462306a36Sopenharmony_ci * Returns: 1 if APQN exists and info is filled, 35562306a36Sopenharmony_ci * 0 if APQN seems to exit but there is no info 35662306a36Sopenharmony_ci * available (eg. caused by an asynch pending error) 35762306a36Sopenharmony_ci * -1 invalid APQN, TAPQ error or AP queue status which 35862306a36Sopenharmony_ci * indicates there is no APQN. 35962306a36Sopenharmony_ci */ 36062306a36Sopenharmony_cistatic int ap_queue_info(ap_qid_t qid, int *q_type, unsigned int *q_fac, 36162306a36Sopenharmony_ci int *q_depth, int *q_ml, bool *q_decfg, bool *q_cstop) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci struct ap_queue_status status; 36462306a36Sopenharmony_ci struct ap_tapq_gr2 tapq_info; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci tapq_info.value = 0; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci /* make sure we don't run into a specifiation exception */ 36962306a36Sopenharmony_ci if (AP_QID_CARD(qid) > ap_max_adapter_id || 37062306a36Sopenharmony_ci AP_QID_QUEUE(qid) > ap_max_domain_id) 37162306a36Sopenharmony_ci return -1; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci /* call TAPQ on this APQN */ 37462306a36Sopenharmony_ci status = ap_test_queue(qid, ap_apft_available(), &tapq_info); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci /* handle pending async error with return 'no info available' */ 37762306a36Sopenharmony_ci if (status.async) 37862306a36Sopenharmony_ci return 0; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci switch (status.response_code) { 38162306a36Sopenharmony_ci case AP_RESPONSE_NORMAL: 38262306a36Sopenharmony_ci case AP_RESPONSE_RESET_IN_PROGRESS: 38362306a36Sopenharmony_ci case AP_RESPONSE_DECONFIGURED: 38462306a36Sopenharmony_ci case AP_RESPONSE_CHECKSTOPPED: 38562306a36Sopenharmony_ci case AP_RESPONSE_BUSY: 38662306a36Sopenharmony_ci /* 38762306a36Sopenharmony_ci * According to the architecture in all these cases the 38862306a36Sopenharmony_ci * info should be filled. All bits 0 is not possible as 38962306a36Sopenharmony_ci * there is at least one of the mode bits set. 39062306a36Sopenharmony_ci */ 39162306a36Sopenharmony_ci if (WARN_ON_ONCE(!tapq_info.value)) 39262306a36Sopenharmony_ci return 0; 39362306a36Sopenharmony_ci *q_type = tapq_info.at; 39462306a36Sopenharmony_ci *q_fac = tapq_info.fac; 39562306a36Sopenharmony_ci *q_depth = tapq_info.qd; 39662306a36Sopenharmony_ci *q_ml = tapq_info.ml; 39762306a36Sopenharmony_ci *q_decfg = status.response_code == AP_RESPONSE_DECONFIGURED; 39862306a36Sopenharmony_ci *q_cstop = status.response_code == AP_RESPONSE_CHECKSTOPPED; 39962306a36Sopenharmony_ci return 1; 40062306a36Sopenharmony_ci default: 40162306a36Sopenharmony_ci /* 40262306a36Sopenharmony_ci * A response code which indicates, there is no info available. 40362306a36Sopenharmony_ci */ 40462306a36Sopenharmony_ci return -1; 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_civoid ap_wait(enum ap_sm_wait wait) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci ktime_t hr_time; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci switch (wait) { 41362306a36Sopenharmony_ci case AP_SM_WAIT_AGAIN: 41462306a36Sopenharmony_ci case AP_SM_WAIT_INTERRUPT: 41562306a36Sopenharmony_ci if (ap_irq_flag) 41662306a36Sopenharmony_ci break; 41762306a36Sopenharmony_ci if (ap_poll_kthread) { 41862306a36Sopenharmony_ci wake_up(&ap_poll_wait); 41962306a36Sopenharmony_ci break; 42062306a36Sopenharmony_ci } 42162306a36Sopenharmony_ci fallthrough; 42262306a36Sopenharmony_ci case AP_SM_WAIT_LOW_TIMEOUT: 42362306a36Sopenharmony_ci case AP_SM_WAIT_HIGH_TIMEOUT: 42462306a36Sopenharmony_ci spin_lock_bh(&ap_poll_timer_lock); 42562306a36Sopenharmony_ci if (!hrtimer_is_queued(&ap_poll_timer)) { 42662306a36Sopenharmony_ci hr_time = 42762306a36Sopenharmony_ci wait == AP_SM_WAIT_LOW_TIMEOUT ? 42862306a36Sopenharmony_ci poll_low_timeout : poll_high_timeout; 42962306a36Sopenharmony_ci hrtimer_forward_now(&ap_poll_timer, hr_time); 43062306a36Sopenharmony_ci hrtimer_restart(&ap_poll_timer); 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci spin_unlock_bh(&ap_poll_timer_lock); 43362306a36Sopenharmony_ci break; 43462306a36Sopenharmony_ci case AP_SM_WAIT_NONE: 43562306a36Sopenharmony_ci default: 43662306a36Sopenharmony_ci break; 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci/** 44162306a36Sopenharmony_ci * ap_request_timeout(): Handling of request timeouts 44262306a36Sopenharmony_ci * @t: timer making this callback 44362306a36Sopenharmony_ci * 44462306a36Sopenharmony_ci * Handles request timeouts. 44562306a36Sopenharmony_ci */ 44662306a36Sopenharmony_civoid ap_request_timeout(struct timer_list *t) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci struct ap_queue *aq = from_timer(aq, t, timeout); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci spin_lock_bh(&aq->lock); 45162306a36Sopenharmony_ci ap_wait(ap_sm_event(aq, AP_SM_EVENT_TIMEOUT)); 45262306a36Sopenharmony_ci spin_unlock_bh(&aq->lock); 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci/** 45662306a36Sopenharmony_ci * ap_poll_timeout(): AP receive polling for finished AP requests. 45762306a36Sopenharmony_ci * @unused: Unused pointer. 45862306a36Sopenharmony_ci * 45962306a36Sopenharmony_ci * Schedules the AP tasklet using a high resolution timer. 46062306a36Sopenharmony_ci */ 46162306a36Sopenharmony_cistatic enum hrtimer_restart ap_poll_timeout(struct hrtimer *unused) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci tasklet_schedule(&ap_tasklet); 46462306a36Sopenharmony_ci return HRTIMER_NORESTART; 46562306a36Sopenharmony_ci} 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci/** 46862306a36Sopenharmony_ci * ap_interrupt_handler() - Schedule ap_tasklet on interrupt 46962306a36Sopenharmony_ci * @airq: pointer to adapter interrupt descriptor 47062306a36Sopenharmony_ci * @tpi_info: ignored 47162306a36Sopenharmony_ci */ 47262306a36Sopenharmony_cistatic void ap_interrupt_handler(struct airq_struct *airq, 47362306a36Sopenharmony_ci struct tpi_info *tpi_info) 47462306a36Sopenharmony_ci{ 47562306a36Sopenharmony_ci inc_irq_stat(IRQIO_APB); 47662306a36Sopenharmony_ci tasklet_schedule(&ap_tasklet); 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci/** 48062306a36Sopenharmony_ci * ap_tasklet_fn(): Tasklet to poll all AP devices. 48162306a36Sopenharmony_ci * @dummy: Unused variable 48262306a36Sopenharmony_ci * 48362306a36Sopenharmony_ci * Poll all AP devices on the bus. 48462306a36Sopenharmony_ci */ 48562306a36Sopenharmony_cistatic void ap_tasklet_fn(unsigned long dummy) 48662306a36Sopenharmony_ci{ 48762306a36Sopenharmony_ci int bkt; 48862306a36Sopenharmony_ci struct ap_queue *aq; 48962306a36Sopenharmony_ci enum ap_sm_wait wait = AP_SM_WAIT_NONE; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci /* Reset the indicator if interrupts are used. Thus new interrupts can 49262306a36Sopenharmony_ci * be received. Doing it in the beginning of the tasklet is therefore 49362306a36Sopenharmony_ci * important that no requests on any AP get lost. 49462306a36Sopenharmony_ci */ 49562306a36Sopenharmony_ci if (ap_irq_flag) 49662306a36Sopenharmony_ci xchg(ap_airq.lsi_ptr, 0); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci spin_lock_bh(&ap_queues_lock); 49962306a36Sopenharmony_ci hash_for_each(ap_queues, bkt, aq, hnode) { 50062306a36Sopenharmony_ci spin_lock_bh(&aq->lock); 50162306a36Sopenharmony_ci wait = min(wait, ap_sm_event_loop(aq, AP_SM_EVENT_POLL)); 50262306a36Sopenharmony_ci spin_unlock_bh(&aq->lock); 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci spin_unlock_bh(&ap_queues_lock); 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci ap_wait(wait); 50762306a36Sopenharmony_ci} 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_cistatic int ap_pending_requests(void) 51062306a36Sopenharmony_ci{ 51162306a36Sopenharmony_ci int bkt; 51262306a36Sopenharmony_ci struct ap_queue *aq; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci spin_lock_bh(&ap_queues_lock); 51562306a36Sopenharmony_ci hash_for_each(ap_queues, bkt, aq, hnode) { 51662306a36Sopenharmony_ci if (aq->queue_count == 0) 51762306a36Sopenharmony_ci continue; 51862306a36Sopenharmony_ci spin_unlock_bh(&ap_queues_lock); 51962306a36Sopenharmony_ci return 1; 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci spin_unlock_bh(&ap_queues_lock); 52262306a36Sopenharmony_ci return 0; 52362306a36Sopenharmony_ci} 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci/** 52662306a36Sopenharmony_ci * ap_poll_thread(): Thread that polls for finished requests. 52762306a36Sopenharmony_ci * @data: Unused pointer 52862306a36Sopenharmony_ci * 52962306a36Sopenharmony_ci * AP bus poll thread. The purpose of this thread is to poll for 53062306a36Sopenharmony_ci * finished requests in a loop if there is a "free" cpu - that is 53162306a36Sopenharmony_ci * a cpu that doesn't have anything better to do. The polling stops 53262306a36Sopenharmony_ci * as soon as there is another task or if all messages have been 53362306a36Sopenharmony_ci * delivered. 53462306a36Sopenharmony_ci */ 53562306a36Sopenharmony_cistatic int ap_poll_thread(void *data) 53662306a36Sopenharmony_ci{ 53762306a36Sopenharmony_ci DECLARE_WAITQUEUE(wait, current); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci set_user_nice(current, MAX_NICE); 54062306a36Sopenharmony_ci set_freezable(); 54162306a36Sopenharmony_ci while (!kthread_should_stop()) { 54262306a36Sopenharmony_ci add_wait_queue(&ap_poll_wait, &wait); 54362306a36Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 54462306a36Sopenharmony_ci if (!ap_pending_requests()) { 54562306a36Sopenharmony_ci schedule(); 54662306a36Sopenharmony_ci try_to_freeze(); 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci set_current_state(TASK_RUNNING); 54962306a36Sopenharmony_ci remove_wait_queue(&ap_poll_wait, &wait); 55062306a36Sopenharmony_ci if (need_resched()) { 55162306a36Sopenharmony_ci schedule(); 55262306a36Sopenharmony_ci try_to_freeze(); 55362306a36Sopenharmony_ci continue; 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci ap_tasklet_fn(0); 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci return 0; 55962306a36Sopenharmony_ci} 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_cistatic int ap_poll_thread_start(void) 56262306a36Sopenharmony_ci{ 56362306a36Sopenharmony_ci int rc; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci if (ap_irq_flag || ap_poll_kthread) 56662306a36Sopenharmony_ci return 0; 56762306a36Sopenharmony_ci mutex_lock(&ap_poll_thread_mutex); 56862306a36Sopenharmony_ci ap_poll_kthread = kthread_run(ap_poll_thread, NULL, "appoll"); 56962306a36Sopenharmony_ci rc = PTR_ERR_OR_ZERO(ap_poll_kthread); 57062306a36Sopenharmony_ci if (rc) 57162306a36Sopenharmony_ci ap_poll_kthread = NULL; 57262306a36Sopenharmony_ci mutex_unlock(&ap_poll_thread_mutex); 57362306a36Sopenharmony_ci return rc; 57462306a36Sopenharmony_ci} 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_cistatic void ap_poll_thread_stop(void) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci if (!ap_poll_kthread) 57962306a36Sopenharmony_ci return; 58062306a36Sopenharmony_ci mutex_lock(&ap_poll_thread_mutex); 58162306a36Sopenharmony_ci kthread_stop(ap_poll_kthread); 58262306a36Sopenharmony_ci ap_poll_kthread = NULL; 58362306a36Sopenharmony_ci mutex_unlock(&ap_poll_thread_mutex); 58462306a36Sopenharmony_ci} 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci#define is_card_dev(x) ((x)->parent == ap_root_device) 58762306a36Sopenharmony_ci#define is_queue_dev(x) ((x)->parent != ap_root_device) 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci/** 59062306a36Sopenharmony_ci * ap_bus_match() 59162306a36Sopenharmony_ci * @dev: Pointer to device 59262306a36Sopenharmony_ci * @drv: Pointer to device_driver 59362306a36Sopenharmony_ci * 59462306a36Sopenharmony_ci * AP bus driver registration/unregistration. 59562306a36Sopenharmony_ci */ 59662306a36Sopenharmony_cistatic int ap_bus_match(struct device *dev, struct device_driver *drv) 59762306a36Sopenharmony_ci{ 59862306a36Sopenharmony_ci struct ap_driver *ap_drv = to_ap_drv(drv); 59962306a36Sopenharmony_ci struct ap_device_id *id; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci /* 60262306a36Sopenharmony_ci * Compare device type of the device with the list of 60362306a36Sopenharmony_ci * supported types of the device_driver. 60462306a36Sopenharmony_ci */ 60562306a36Sopenharmony_ci for (id = ap_drv->ids; id->match_flags; id++) { 60662306a36Sopenharmony_ci if (is_card_dev(dev) && 60762306a36Sopenharmony_ci id->match_flags & AP_DEVICE_ID_MATCH_CARD_TYPE && 60862306a36Sopenharmony_ci id->dev_type == to_ap_dev(dev)->device_type) 60962306a36Sopenharmony_ci return 1; 61062306a36Sopenharmony_ci if (is_queue_dev(dev) && 61162306a36Sopenharmony_ci id->match_flags & AP_DEVICE_ID_MATCH_QUEUE_TYPE && 61262306a36Sopenharmony_ci id->dev_type == to_ap_dev(dev)->device_type) 61362306a36Sopenharmony_ci return 1; 61462306a36Sopenharmony_ci } 61562306a36Sopenharmony_ci return 0; 61662306a36Sopenharmony_ci} 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci/** 61962306a36Sopenharmony_ci * ap_uevent(): Uevent function for AP devices. 62062306a36Sopenharmony_ci * @dev: Pointer to device 62162306a36Sopenharmony_ci * @env: Pointer to kobj_uevent_env 62262306a36Sopenharmony_ci * 62362306a36Sopenharmony_ci * It sets up a single environment variable DEV_TYPE which contains the 62462306a36Sopenharmony_ci * hardware device type. 62562306a36Sopenharmony_ci */ 62662306a36Sopenharmony_cistatic int ap_uevent(const struct device *dev, struct kobj_uevent_env *env) 62762306a36Sopenharmony_ci{ 62862306a36Sopenharmony_ci int rc = 0; 62962306a36Sopenharmony_ci const struct ap_device *ap_dev = to_ap_dev(dev); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci /* Uevents from ap bus core don't need extensions to the env */ 63262306a36Sopenharmony_ci if (dev == ap_root_device) 63362306a36Sopenharmony_ci return 0; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci if (is_card_dev(dev)) { 63662306a36Sopenharmony_ci struct ap_card *ac = to_ap_card(&ap_dev->device); 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci /* Set up DEV_TYPE environment variable. */ 63962306a36Sopenharmony_ci rc = add_uevent_var(env, "DEV_TYPE=%04X", ap_dev->device_type); 64062306a36Sopenharmony_ci if (rc) 64162306a36Sopenharmony_ci return rc; 64262306a36Sopenharmony_ci /* Add MODALIAS= */ 64362306a36Sopenharmony_ci rc = add_uevent_var(env, "MODALIAS=ap:t%02X", ap_dev->device_type); 64462306a36Sopenharmony_ci if (rc) 64562306a36Sopenharmony_ci return rc; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci /* Add MODE=<accel|cca|ep11> */ 64862306a36Sopenharmony_ci if (ap_test_bit(&ac->functions, AP_FUNC_ACCEL)) 64962306a36Sopenharmony_ci rc = add_uevent_var(env, "MODE=accel"); 65062306a36Sopenharmony_ci else if (ap_test_bit(&ac->functions, AP_FUNC_COPRO)) 65162306a36Sopenharmony_ci rc = add_uevent_var(env, "MODE=cca"); 65262306a36Sopenharmony_ci else if (ap_test_bit(&ac->functions, AP_FUNC_EP11)) 65362306a36Sopenharmony_ci rc = add_uevent_var(env, "MODE=ep11"); 65462306a36Sopenharmony_ci if (rc) 65562306a36Sopenharmony_ci return rc; 65662306a36Sopenharmony_ci } else { 65762306a36Sopenharmony_ci struct ap_queue *aq = to_ap_queue(&ap_dev->device); 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci /* Add MODE=<accel|cca|ep11> */ 66062306a36Sopenharmony_ci if (ap_test_bit(&aq->card->functions, AP_FUNC_ACCEL)) 66162306a36Sopenharmony_ci rc = add_uevent_var(env, "MODE=accel"); 66262306a36Sopenharmony_ci else if (ap_test_bit(&aq->card->functions, AP_FUNC_COPRO)) 66362306a36Sopenharmony_ci rc = add_uevent_var(env, "MODE=cca"); 66462306a36Sopenharmony_ci else if (ap_test_bit(&aq->card->functions, AP_FUNC_EP11)) 66562306a36Sopenharmony_ci rc = add_uevent_var(env, "MODE=ep11"); 66662306a36Sopenharmony_ci if (rc) 66762306a36Sopenharmony_ci return rc; 66862306a36Sopenharmony_ci } 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci return 0; 67162306a36Sopenharmony_ci} 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_cistatic void ap_send_init_scan_done_uevent(void) 67462306a36Sopenharmony_ci{ 67562306a36Sopenharmony_ci char *envp[] = { "INITSCAN=done", NULL }; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci kobject_uevent_env(&ap_root_device->kobj, KOBJ_CHANGE, envp); 67862306a36Sopenharmony_ci} 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_cistatic void ap_send_bindings_complete_uevent(void) 68162306a36Sopenharmony_ci{ 68262306a36Sopenharmony_ci char buf[32]; 68362306a36Sopenharmony_ci char *envp[] = { "BINDINGS=complete", buf, NULL }; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci snprintf(buf, sizeof(buf), "COMPLETECOUNT=%llu", 68662306a36Sopenharmony_ci atomic64_inc_return(&ap_bindings_complete_count)); 68762306a36Sopenharmony_ci kobject_uevent_env(&ap_root_device->kobj, KOBJ_CHANGE, envp); 68862306a36Sopenharmony_ci} 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_civoid ap_send_config_uevent(struct ap_device *ap_dev, bool cfg) 69162306a36Sopenharmony_ci{ 69262306a36Sopenharmony_ci char buf[16]; 69362306a36Sopenharmony_ci char *envp[] = { buf, NULL }; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci snprintf(buf, sizeof(buf), "CONFIG=%d", cfg ? 1 : 0); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci kobject_uevent_env(&ap_dev->device.kobj, KOBJ_CHANGE, envp); 69862306a36Sopenharmony_ci} 69962306a36Sopenharmony_ciEXPORT_SYMBOL(ap_send_config_uevent); 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_civoid ap_send_online_uevent(struct ap_device *ap_dev, int online) 70262306a36Sopenharmony_ci{ 70362306a36Sopenharmony_ci char buf[16]; 70462306a36Sopenharmony_ci char *envp[] = { buf, NULL }; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci snprintf(buf, sizeof(buf), "ONLINE=%d", online ? 1 : 0); 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci kobject_uevent_env(&ap_dev->device.kobj, KOBJ_CHANGE, envp); 70962306a36Sopenharmony_ci} 71062306a36Sopenharmony_ciEXPORT_SYMBOL(ap_send_online_uevent); 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_cistatic void ap_send_mask_changed_uevent(unsigned long *newapm, 71362306a36Sopenharmony_ci unsigned long *newaqm) 71462306a36Sopenharmony_ci{ 71562306a36Sopenharmony_ci char buf[100]; 71662306a36Sopenharmony_ci char *envp[] = { buf, NULL }; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci if (newapm) 71962306a36Sopenharmony_ci snprintf(buf, sizeof(buf), 72062306a36Sopenharmony_ci "APMASK=0x%016lx%016lx%016lx%016lx\n", 72162306a36Sopenharmony_ci newapm[0], newapm[1], newapm[2], newapm[3]); 72262306a36Sopenharmony_ci else 72362306a36Sopenharmony_ci snprintf(buf, sizeof(buf), 72462306a36Sopenharmony_ci "AQMASK=0x%016lx%016lx%016lx%016lx\n", 72562306a36Sopenharmony_ci newaqm[0], newaqm[1], newaqm[2], newaqm[3]); 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci kobject_uevent_env(&ap_root_device->kobj, KOBJ_CHANGE, envp); 72862306a36Sopenharmony_ci} 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci/* 73162306a36Sopenharmony_ci * calc # of bound APQNs 73262306a36Sopenharmony_ci */ 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_cistruct __ap_calc_ctrs { 73562306a36Sopenharmony_ci unsigned int apqns; 73662306a36Sopenharmony_ci unsigned int bound; 73762306a36Sopenharmony_ci}; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_cistatic int __ap_calc_helper(struct device *dev, void *arg) 74062306a36Sopenharmony_ci{ 74162306a36Sopenharmony_ci struct __ap_calc_ctrs *pctrs = (struct __ap_calc_ctrs *)arg; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci if (is_queue_dev(dev)) { 74462306a36Sopenharmony_ci pctrs->apqns++; 74562306a36Sopenharmony_ci if (dev->driver) 74662306a36Sopenharmony_ci pctrs->bound++; 74762306a36Sopenharmony_ci } 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci return 0; 75062306a36Sopenharmony_ci} 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_cistatic void ap_calc_bound_apqns(unsigned int *apqns, unsigned int *bound) 75362306a36Sopenharmony_ci{ 75462306a36Sopenharmony_ci struct __ap_calc_ctrs ctrs; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci memset(&ctrs, 0, sizeof(ctrs)); 75762306a36Sopenharmony_ci bus_for_each_dev(&ap_bus_type, NULL, (void *)&ctrs, __ap_calc_helper); 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci *apqns = ctrs.apqns; 76062306a36Sopenharmony_ci *bound = ctrs.bound; 76162306a36Sopenharmony_ci} 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci/* 76462306a36Sopenharmony_ci * After initial ap bus scan do check if all existing APQNs are 76562306a36Sopenharmony_ci * bound to device drivers. 76662306a36Sopenharmony_ci */ 76762306a36Sopenharmony_cistatic void ap_check_bindings_complete(void) 76862306a36Sopenharmony_ci{ 76962306a36Sopenharmony_ci unsigned int apqns, bound; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci if (atomic64_read(&ap_scan_bus_count) >= 1) { 77262306a36Sopenharmony_ci ap_calc_bound_apqns(&apqns, &bound); 77362306a36Sopenharmony_ci if (bound == apqns) { 77462306a36Sopenharmony_ci if (!completion_done(&ap_init_apqn_bindings_complete)) { 77562306a36Sopenharmony_ci complete_all(&ap_init_apqn_bindings_complete); 77662306a36Sopenharmony_ci AP_DBF_INFO("%s complete\n", __func__); 77762306a36Sopenharmony_ci } 77862306a36Sopenharmony_ci ap_send_bindings_complete_uevent(); 77962306a36Sopenharmony_ci } 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci} 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci/* 78462306a36Sopenharmony_ci * Interface to wait for the AP bus to have done one initial ap bus 78562306a36Sopenharmony_ci * scan and all detected APQNs have been bound to device drivers. 78662306a36Sopenharmony_ci * If these both conditions are not fulfilled, this function blocks 78762306a36Sopenharmony_ci * on a condition with wait_for_completion_interruptible_timeout(). 78862306a36Sopenharmony_ci * If these both conditions are fulfilled (before the timeout hits) 78962306a36Sopenharmony_ci * the return value is 0. If the timeout (in jiffies) hits instead 79062306a36Sopenharmony_ci * -ETIME is returned. On failures negative return values are 79162306a36Sopenharmony_ci * returned to the caller. 79262306a36Sopenharmony_ci */ 79362306a36Sopenharmony_ciint ap_wait_init_apqn_bindings_complete(unsigned long timeout) 79462306a36Sopenharmony_ci{ 79562306a36Sopenharmony_ci long l; 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci if (completion_done(&ap_init_apqn_bindings_complete)) 79862306a36Sopenharmony_ci return 0; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci if (timeout) 80162306a36Sopenharmony_ci l = wait_for_completion_interruptible_timeout( 80262306a36Sopenharmony_ci &ap_init_apqn_bindings_complete, timeout); 80362306a36Sopenharmony_ci else 80462306a36Sopenharmony_ci l = wait_for_completion_interruptible( 80562306a36Sopenharmony_ci &ap_init_apqn_bindings_complete); 80662306a36Sopenharmony_ci if (l < 0) 80762306a36Sopenharmony_ci return l == -ERESTARTSYS ? -EINTR : l; 80862306a36Sopenharmony_ci else if (l == 0 && timeout) 80962306a36Sopenharmony_ci return -ETIME; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci return 0; 81262306a36Sopenharmony_ci} 81362306a36Sopenharmony_ciEXPORT_SYMBOL(ap_wait_init_apqn_bindings_complete); 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_cistatic int __ap_queue_devices_with_id_unregister(struct device *dev, void *data) 81662306a36Sopenharmony_ci{ 81762306a36Sopenharmony_ci if (is_queue_dev(dev) && 81862306a36Sopenharmony_ci AP_QID_CARD(to_ap_queue(dev)->qid) == (int)(long)data) 81962306a36Sopenharmony_ci device_unregister(dev); 82062306a36Sopenharmony_ci return 0; 82162306a36Sopenharmony_ci} 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_cistatic int __ap_revise_reserved(struct device *dev, void *dummy) 82462306a36Sopenharmony_ci{ 82562306a36Sopenharmony_ci int rc, card, queue, devres, drvres; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci if (is_queue_dev(dev)) { 82862306a36Sopenharmony_ci card = AP_QID_CARD(to_ap_queue(dev)->qid); 82962306a36Sopenharmony_ci queue = AP_QID_QUEUE(to_ap_queue(dev)->qid); 83062306a36Sopenharmony_ci mutex_lock(&ap_perms_mutex); 83162306a36Sopenharmony_ci devres = test_bit_inv(card, ap_perms.apm) && 83262306a36Sopenharmony_ci test_bit_inv(queue, ap_perms.aqm); 83362306a36Sopenharmony_ci mutex_unlock(&ap_perms_mutex); 83462306a36Sopenharmony_ci drvres = to_ap_drv(dev->driver)->flags 83562306a36Sopenharmony_ci & AP_DRIVER_FLAG_DEFAULT; 83662306a36Sopenharmony_ci if (!!devres != !!drvres) { 83762306a36Sopenharmony_ci AP_DBF_DBG("%s reprobing queue=%02x.%04x\n", 83862306a36Sopenharmony_ci __func__, card, queue); 83962306a36Sopenharmony_ci rc = device_reprobe(dev); 84062306a36Sopenharmony_ci if (rc) 84162306a36Sopenharmony_ci AP_DBF_WARN("%s reprobing queue=%02x.%04x failed\n", 84262306a36Sopenharmony_ci __func__, card, queue); 84362306a36Sopenharmony_ci } 84462306a36Sopenharmony_ci } 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci return 0; 84762306a36Sopenharmony_ci} 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_cistatic void ap_bus_revise_bindings(void) 85062306a36Sopenharmony_ci{ 85162306a36Sopenharmony_ci bus_for_each_dev(&ap_bus_type, NULL, NULL, __ap_revise_reserved); 85262306a36Sopenharmony_ci} 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci/** 85562306a36Sopenharmony_ci * ap_owned_by_def_drv: indicates whether an AP adapter is reserved for the 85662306a36Sopenharmony_ci * default host driver or not. 85762306a36Sopenharmony_ci * @card: the APID of the adapter card to check 85862306a36Sopenharmony_ci * @queue: the APQI of the queue to check 85962306a36Sopenharmony_ci * 86062306a36Sopenharmony_ci * Note: the ap_perms_mutex must be locked by the caller of this function. 86162306a36Sopenharmony_ci * 86262306a36Sopenharmony_ci * Return: an int specifying whether the AP adapter is reserved for the host (1) 86362306a36Sopenharmony_ci * or not (0). 86462306a36Sopenharmony_ci */ 86562306a36Sopenharmony_ciint ap_owned_by_def_drv(int card, int queue) 86662306a36Sopenharmony_ci{ 86762306a36Sopenharmony_ci int rc = 0; 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci if (card < 0 || card >= AP_DEVICES || queue < 0 || queue >= AP_DOMAINS) 87062306a36Sopenharmony_ci return -EINVAL; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci if (test_bit_inv(card, ap_perms.apm) && 87362306a36Sopenharmony_ci test_bit_inv(queue, ap_perms.aqm)) 87462306a36Sopenharmony_ci rc = 1; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci return rc; 87762306a36Sopenharmony_ci} 87862306a36Sopenharmony_ciEXPORT_SYMBOL(ap_owned_by_def_drv); 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci/** 88162306a36Sopenharmony_ci * ap_apqn_in_matrix_owned_by_def_drv: indicates whether every APQN contained in 88262306a36Sopenharmony_ci * a set is reserved for the host drivers 88362306a36Sopenharmony_ci * or not. 88462306a36Sopenharmony_ci * @apm: a bitmap specifying a set of APIDs comprising the APQNs to check 88562306a36Sopenharmony_ci * @aqm: a bitmap specifying a set of APQIs comprising the APQNs to check 88662306a36Sopenharmony_ci * 88762306a36Sopenharmony_ci * Note: the ap_perms_mutex must be locked by the caller of this function. 88862306a36Sopenharmony_ci * 88962306a36Sopenharmony_ci * Return: an int specifying whether each APQN is reserved for the host (1) or 89062306a36Sopenharmony_ci * not (0) 89162306a36Sopenharmony_ci */ 89262306a36Sopenharmony_ciint ap_apqn_in_matrix_owned_by_def_drv(unsigned long *apm, 89362306a36Sopenharmony_ci unsigned long *aqm) 89462306a36Sopenharmony_ci{ 89562306a36Sopenharmony_ci int card, queue, rc = 0; 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci for (card = 0; !rc && card < AP_DEVICES; card++) 89862306a36Sopenharmony_ci if (test_bit_inv(card, apm) && 89962306a36Sopenharmony_ci test_bit_inv(card, ap_perms.apm)) 90062306a36Sopenharmony_ci for (queue = 0; !rc && queue < AP_DOMAINS; queue++) 90162306a36Sopenharmony_ci if (test_bit_inv(queue, aqm) && 90262306a36Sopenharmony_ci test_bit_inv(queue, ap_perms.aqm)) 90362306a36Sopenharmony_ci rc = 1; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci return rc; 90662306a36Sopenharmony_ci} 90762306a36Sopenharmony_ciEXPORT_SYMBOL(ap_apqn_in_matrix_owned_by_def_drv); 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_cistatic int ap_device_probe(struct device *dev) 91062306a36Sopenharmony_ci{ 91162306a36Sopenharmony_ci struct ap_device *ap_dev = to_ap_dev(dev); 91262306a36Sopenharmony_ci struct ap_driver *ap_drv = to_ap_drv(dev->driver); 91362306a36Sopenharmony_ci int card, queue, devres, drvres, rc = -ENODEV; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci if (!get_device(dev)) 91662306a36Sopenharmony_ci return rc; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci if (is_queue_dev(dev)) { 91962306a36Sopenharmony_ci /* 92062306a36Sopenharmony_ci * If the apqn is marked as reserved/used by ap bus and 92162306a36Sopenharmony_ci * default drivers, only probe with drivers with the default 92262306a36Sopenharmony_ci * flag set. If it is not marked, only probe with drivers 92362306a36Sopenharmony_ci * with the default flag not set. 92462306a36Sopenharmony_ci */ 92562306a36Sopenharmony_ci card = AP_QID_CARD(to_ap_queue(dev)->qid); 92662306a36Sopenharmony_ci queue = AP_QID_QUEUE(to_ap_queue(dev)->qid); 92762306a36Sopenharmony_ci mutex_lock(&ap_perms_mutex); 92862306a36Sopenharmony_ci devres = test_bit_inv(card, ap_perms.apm) && 92962306a36Sopenharmony_ci test_bit_inv(queue, ap_perms.aqm); 93062306a36Sopenharmony_ci mutex_unlock(&ap_perms_mutex); 93162306a36Sopenharmony_ci drvres = ap_drv->flags & AP_DRIVER_FLAG_DEFAULT; 93262306a36Sopenharmony_ci if (!!devres != !!drvres) 93362306a36Sopenharmony_ci goto out; 93462306a36Sopenharmony_ci } 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci /* Add queue/card to list of active queues/cards */ 93762306a36Sopenharmony_ci spin_lock_bh(&ap_queues_lock); 93862306a36Sopenharmony_ci if (is_queue_dev(dev)) 93962306a36Sopenharmony_ci hash_add(ap_queues, &to_ap_queue(dev)->hnode, 94062306a36Sopenharmony_ci to_ap_queue(dev)->qid); 94162306a36Sopenharmony_ci spin_unlock_bh(&ap_queues_lock); 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci rc = ap_drv->probe ? ap_drv->probe(ap_dev) : -ENODEV; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci if (rc) { 94662306a36Sopenharmony_ci spin_lock_bh(&ap_queues_lock); 94762306a36Sopenharmony_ci if (is_queue_dev(dev)) 94862306a36Sopenharmony_ci hash_del(&to_ap_queue(dev)->hnode); 94962306a36Sopenharmony_ci spin_unlock_bh(&ap_queues_lock); 95062306a36Sopenharmony_ci } else { 95162306a36Sopenharmony_ci ap_check_bindings_complete(); 95262306a36Sopenharmony_ci } 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ciout: 95562306a36Sopenharmony_ci if (rc) 95662306a36Sopenharmony_ci put_device(dev); 95762306a36Sopenharmony_ci return rc; 95862306a36Sopenharmony_ci} 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_cistatic void ap_device_remove(struct device *dev) 96162306a36Sopenharmony_ci{ 96262306a36Sopenharmony_ci struct ap_device *ap_dev = to_ap_dev(dev); 96362306a36Sopenharmony_ci struct ap_driver *ap_drv = to_ap_drv(dev->driver); 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci /* prepare ap queue device removal */ 96662306a36Sopenharmony_ci if (is_queue_dev(dev)) 96762306a36Sopenharmony_ci ap_queue_prepare_remove(to_ap_queue(dev)); 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci /* driver's chance to clean up gracefully */ 97062306a36Sopenharmony_ci if (ap_drv->remove) 97162306a36Sopenharmony_ci ap_drv->remove(ap_dev); 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci /* now do the ap queue device remove */ 97462306a36Sopenharmony_ci if (is_queue_dev(dev)) 97562306a36Sopenharmony_ci ap_queue_remove(to_ap_queue(dev)); 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci /* Remove queue/card from list of active queues/cards */ 97862306a36Sopenharmony_ci spin_lock_bh(&ap_queues_lock); 97962306a36Sopenharmony_ci if (is_queue_dev(dev)) 98062306a36Sopenharmony_ci hash_del(&to_ap_queue(dev)->hnode); 98162306a36Sopenharmony_ci spin_unlock_bh(&ap_queues_lock); 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci put_device(dev); 98462306a36Sopenharmony_ci} 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_cistruct ap_queue *ap_get_qdev(ap_qid_t qid) 98762306a36Sopenharmony_ci{ 98862306a36Sopenharmony_ci int bkt; 98962306a36Sopenharmony_ci struct ap_queue *aq; 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci spin_lock_bh(&ap_queues_lock); 99262306a36Sopenharmony_ci hash_for_each(ap_queues, bkt, aq, hnode) { 99362306a36Sopenharmony_ci if (aq->qid == qid) { 99462306a36Sopenharmony_ci get_device(&aq->ap_dev.device); 99562306a36Sopenharmony_ci spin_unlock_bh(&ap_queues_lock); 99662306a36Sopenharmony_ci return aq; 99762306a36Sopenharmony_ci } 99862306a36Sopenharmony_ci } 99962306a36Sopenharmony_ci spin_unlock_bh(&ap_queues_lock); 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci return NULL; 100262306a36Sopenharmony_ci} 100362306a36Sopenharmony_ciEXPORT_SYMBOL(ap_get_qdev); 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ciint ap_driver_register(struct ap_driver *ap_drv, struct module *owner, 100662306a36Sopenharmony_ci char *name) 100762306a36Sopenharmony_ci{ 100862306a36Sopenharmony_ci struct device_driver *drv = &ap_drv->driver; 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci drv->bus = &ap_bus_type; 101162306a36Sopenharmony_ci drv->owner = owner; 101262306a36Sopenharmony_ci drv->name = name; 101362306a36Sopenharmony_ci return driver_register(drv); 101462306a36Sopenharmony_ci} 101562306a36Sopenharmony_ciEXPORT_SYMBOL(ap_driver_register); 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_civoid ap_driver_unregister(struct ap_driver *ap_drv) 101862306a36Sopenharmony_ci{ 101962306a36Sopenharmony_ci driver_unregister(&ap_drv->driver); 102062306a36Sopenharmony_ci} 102162306a36Sopenharmony_ciEXPORT_SYMBOL(ap_driver_unregister); 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_civoid ap_bus_force_rescan(void) 102462306a36Sopenharmony_ci{ 102562306a36Sopenharmony_ci /* Only trigger AP bus scans after the initial scan is done */ 102662306a36Sopenharmony_ci if (atomic64_read(&ap_scan_bus_count) <= 0) 102762306a36Sopenharmony_ci return; 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci /* processing a asynchronous bus rescan */ 103062306a36Sopenharmony_ci del_timer(&ap_config_timer); 103162306a36Sopenharmony_ci queue_work(system_long_wq, &ap_scan_work); 103262306a36Sopenharmony_ci flush_work(&ap_scan_work); 103362306a36Sopenharmony_ci} 103462306a36Sopenharmony_ciEXPORT_SYMBOL(ap_bus_force_rescan); 103562306a36Sopenharmony_ci 103662306a36Sopenharmony_ci/* 103762306a36Sopenharmony_ci * A config change has happened, force an ap bus rescan. 103862306a36Sopenharmony_ci */ 103962306a36Sopenharmony_civoid ap_bus_cfg_chg(void) 104062306a36Sopenharmony_ci{ 104162306a36Sopenharmony_ci AP_DBF_DBG("%s config change, forcing bus rescan\n", __func__); 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci ap_bus_force_rescan(); 104462306a36Sopenharmony_ci} 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci/* 104762306a36Sopenharmony_ci * hex2bitmap() - parse hex mask string and set bitmap. 104862306a36Sopenharmony_ci * Valid strings are "0x012345678" with at least one valid hex number. 104962306a36Sopenharmony_ci * Rest of the bitmap to the right is padded with 0. No spaces allowed 105062306a36Sopenharmony_ci * within the string, the leading 0x may be omitted. 105162306a36Sopenharmony_ci * Returns the bitmask with exactly the bits set as given by the hex 105262306a36Sopenharmony_ci * string (both in big endian order). 105362306a36Sopenharmony_ci */ 105462306a36Sopenharmony_cistatic int hex2bitmap(const char *str, unsigned long *bitmap, int bits) 105562306a36Sopenharmony_ci{ 105662306a36Sopenharmony_ci int i, n, b; 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci /* bits needs to be a multiple of 8 */ 105962306a36Sopenharmony_ci if (bits & 0x07) 106062306a36Sopenharmony_ci return -EINVAL; 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci if (str[0] == '0' && str[1] == 'x') 106362306a36Sopenharmony_ci str++; 106462306a36Sopenharmony_ci if (*str == 'x') 106562306a36Sopenharmony_ci str++; 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci for (i = 0; isxdigit(*str) && i < bits; str++) { 106862306a36Sopenharmony_ci b = hex_to_bin(*str); 106962306a36Sopenharmony_ci for (n = 0; n < 4; n++) 107062306a36Sopenharmony_ci if (b & (0x08 >> n)) 107162306a36Sopenharmony_ci set_bit_inv(i + n, bitmap); 107262306a36Sopenharmony_ci i += 4; 107362306a36Sopenharmony_ci } 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci if (*str == '\n') 107662306a36Sopenharmony_ci str++; 107762306a36Sopenharmony_ci if (*str) 107862306a36Sopenharmony_ci return -EINVAL; 107962306a36Sopenharmony_ci return 0; 108062306a36Sopenharmony_ci} 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci/* 108362306a36Sopenharmony_ci * modify_bitmap() - parse bitmask argument and modify an existing 108462306a36Sopenharmony_ci * bit mask accordingly. A concatenation (done with ',') of these 108562306a36Sopenharmony_ci * terms is recognized: 108662306a36Sopenharmony_ci * +<bitnr>[-<bitnr>] or -<bitnr>[-<bitnr>] 108762306a36Sopenharmony_ci * <bitnr> may be any valid number (hex, decimal or octal) in the range 108862306a36Sopenharmony_ci * 0...bits-1; the leading + or - is required. Here are some examples: 108962306a36Sopenharmony_ci * +0-15,+32,-128,-0xFF 109062306a36Sopenharmony_ci * -0-255,+1-16,+0x128 109162306a36Sopenharmony_ci * +1,+2,+3,+4,-5,-7-10 109262306a36Sopenharmony_ci * Returns the new bitmap after all changes have been applied. Every 109362306a36Sopenharmony_ci * positive value in the string will set a bit and every negative value 109462306a36Sopenharmony_ci * in the string will clear a bit. As a bit may be touched more than once, 109562306a36Sopenharmony_ci * the last 'operation' wins: 109662306a36Sopenharmony_ci * +0-255,-128 = first bits 0-255 will be set, then bit 128 will be 109762306a36Sopenharmony_ci * cleared again. All other bits are unmodified. 109862306a36Sopenharmony_ci */ 109962306a36Sopenharmony_cistatic int modify_bitmap(const char *str, unsigned long *bitmap, int bits) 110062306a36Sopenharmony_ci{ 110162306a36Sopenharmony_ci int a, i, z; 110262306a36Sopenharmony_ci char *np, sign; 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci /* bits needs to be a multiple of 8 */ 110562306a36Sopenharmony_ci if (bits & 0x07) 110662306a36Sopenharmony_ci return -EINVAL; 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci while (*str) { 110962306a36Sopenharmony_ci sign = *str++; 111062306a36Sopenharmony_ci if (sign != '+' && sign != '-') 111162306a36Sopenharmony_ci return -EINVAL; 111262306a36Sopenharmony_ci a = z = simple_strtoul(str, &np, 0); 111362306a36Sopenharmony_ci if (str == np || a >= bits) 111462306a36Sopenharmony_ci return -EINVAL; 111562306a36Sopenharmony_ci str = np; 111662306a36Sopenharmony_ci if (*str == '-') { 111762306a36Sopenharmony_ci z = simple_strtoul(++str, &np, 0); 111862306a36Sopenharmony_ci if (str == np || a > z || z >= bits) 111962306a36Sopenharmony_ci return -EINVAL; 112062306a36Sopenharmony_ci str = np; 112162306a36Sopenharmony_ci } 112262306a36Sopenharmony_ci for (i = a; i <= z; i++) 112362306a36Sopenharmony_ci if (sign == '+') 112462306a36Sopenharmony_ci set_bit_inv(i, bitmap); 112562306a36Sopenharmony_ci else 112662306a36Sopenharmony_ci clear_bit_inv(i, bitmap); 112762306a36Sopenharmony_ci while (*str == ',' || *str == '\n') 112862306a36Sopenharmony_ci str++; 112962306a36Sopenharmony_ci } 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci return 0; 113262306a36Sopenharmony_ci} 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_cistatic int ap_parse_bitmap_str(const char *str, unsigned long *bitmap, int bits, 113562306a36Sopenharmony_ci unsigned long *newmap) 113662306a36Sopenharmony_ci{ 113762306a36Sopenharmony_ci unsigned long size; 113862306a36Sopenharmony_ci int rc; 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci size = BITS_TO_LONGS(bits) * sizeof(unsigned long); 114162306a36Sopenharmony_ci if (*str == '+' || *str == '-') { 114262306a36Sopenharmony_ci memcpy(newmap, bitmap, size); 114362306a36Sopenharmony_ci rc = modify_bitmap(str, newmap, bits); 114462306a36Sopenharmony_ci } else { 114562306a36Sopenharmony_ci memset(newmap, 0, size); 114662306a36Sopenharmony_ci rc = hex2bitmap(str, newmap, bits); 114762306a36Sopenharmony_ci } 114862306a36Sopenharmony_ci return rc; 114962306a36Sopenharmony_ci} 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ciint ap_parse_mask_str(const char *str, 115262306a36Sopenharmony_ci unsigned long *bitmap, int bits, 115362306a36Sopenharmony_ci struct mutex *lock) 115462306a36Sopenharmony_ci{ 115562306a36Sopenharmony_ci unsigned long *newmap, size; 115662306a36Sopenharmony_ci int rc; 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci /* bits needs to be a multiple of 8 */ 115962306a36Sopenharmony_ci if (bits & 0x07) 116062306a36Sopenharmony_ci return -EINVAL; 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci size = BITS_TO_LONGS(bits) * sizeof(unsigned long); 116362306a36Sopenharmony_ci newmap = kmalloc(size, GFP_KERNEL); 116462306a36Sopenharmony_ci if (!newmap) 116562306a36Sopenharmony_ci return -ENOMEM; 116662306a36Sopenharmony_ci if (mutex_lock_interruptible(lock)) { 116762306a36Sopenharmony_ci kfree(newmap); 116862306a36Sopenharmony_ci return -ERESTARTSYS; 116962306a36Sopenharmony_ci } 117062306a36Sopenharmony_ci rc = ap_parse_bitmap_str(str, bitmap, bits, newmap); 117162306a36Sopenharmony_ci if (rc == 0) 117262306a36Sopenharmony_ci memcpy(bitmap, newmap, size); 117362306a36Sopenharmony_ci mutex_unlock(lock); 117462306a36Sopenharmony_ci kfree(newmap); 117562306a36Sopenharmony_ci return rc; 117662306a36Sopenharmony_ci} 117762306a36Sopenharmony_ciEXPORT_SYMBOL(ap_parse_mask_str); 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci/* 118062306a36Sopenharmony_ci * AP bus attributes. 118162306a36Sopenharmony_ci */ 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_cistatic ssize_t ap_domain_show(const struct bus_type *bus, char *buf) 118462306a36Sopenharmony_ci{ 118562306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", ap_domain_index); 118662306a36Sopenharmony_ci} 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_cistatic ssize_t ap_domain_store(const struct bus_type *bus, 118962306a36Sopenharmony_ci const char *buf, size_t count) 119062306a36Sopenharmony_ci{ 119162306a36Sopenharmony_ci int domain; 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci if (sscanf(buf, "%i\n", &domain) != 1 || 119462306a36Sopenharmony_ci domain < 0 || domain > ap_max_domain_id || 119562306a36Sopenharmony_ci !test_bit_inv(domain, ap_perms.aqm)) 119662306a36Sopenharmony_ci return -EINVAL; 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci spin_lock_bh(&ap_domain_lock); 119962306a36Sopenharmony_ci ap_domain_index = domain; 120062306a36Sopenharmony_ci spin_unlock_bh(&ap_domain_lock); 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci AP_DBF_INFO("%s stored new default domain=%d\n", 120362306a36Sopenharmony_ci __func__, domain); 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci return count; 120662306a36Sopenharmony_ci} 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_cistatic BUS_ATTR_RW(ap_domain); 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_cistatic ssize_t ap_control_domain_mask_show(const struct bus_type *bus, char *buf) 121162306a36Sopenharmony_ci{ 121262306a36Sopenharmony_ci if (!ap_qci_info) /* QCI not supported */ 121362306a36Sopenharmony_ci return sysfs_emit(buf, "not supported\n"); 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci return sysfs_emit(buf, "0x%08x%08x%08x%08x%08x%08x%08x%08x\n", 121662306a36Sopenharmony_ci ap_qci_info->adm[0], ap_qci_info->adm[1], 121762306a36Sopenharmony_ci ap_qci_info->adm[2], ap_qci_info->adm[3], 121862306a36Sopenharmony_ci ap_qci_info->adm[4], ap_qci_info->adm[5], 121962306a36Sopenharmony_ci ap_qci_info->adm[6], ap_qci_info->adm[7]); 122062306a36Sopenharmony_ci} 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_cistatic BUS_ATTR_RO(ap_control_domain_mask); 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_cistatic ssize_t ap_usage_domain_mask_show(const struct bus_type *bus, char *buf) 122562306a36Sopenharmony_ci{ 122662306a36Sopenharmony_ci if (!ap_qci_info) /* QCI not supported */ 122762306a36Sopenharmony_ci return sysfs_emit(buf, "not supported\n"); 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci return sysfs_emit(buf, "0x%08x%08x%08x%08x%08x%08x%08x%08x\n", 123062306a36Sopenharmony_ci ap_qci_info->aqm[0], ap_qci_info->aqm[1], 123162306a36Sopenharmony_ci ap_qci_info->aqm[2], ap_qci_info->aqm[3], 123262306a36Sopenharmony_ci ap_qci_info->aqm[4], ap_qci_info->aqm[5], 123362306a36Sopenharmony_ci ap_qci_info->aqm[6], ap_qci_info->aqm[7]); 123462306a36Sopenharmony_ci} 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_cistatic BUS_ATTR_RO(ap_usage_domain_mask); 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_cistatic ssize_t ap_adapter_mask_show(const struct bus_type *bus, char *buf) 123962306a36Sopenharmony_ci{ 124062306a36Sopenharmony_ci if (!ap_qci_info) /* QCI not supported */ 124162306a36Sopenharmony_ci return sysfs_emit(buf, "not supported\n"); 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci return sysfs_emit(buf, "0x%08x%08x%08x%08x%08x%08x%08x%08x\n", 124462306a36Sopenharmony_ci ap_qci_info->apm[0], ap_qci_info->apm[1], 124562306a36Sopenharmony_ci ap_qci_info->apm[2], ap_qci_info->apm[3], 124662306a36Sopenharmony_ci ap_qci_info->apm[4], ap_qci_info->apm[5], 124762306a36Sopenharmony_ci ap_qci_info->apm[6], ap_qci_info->apm[7]); 124862306a36Sopenharmony_ci} 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_cistatic BUS_ATTR_RO(ap_adapter_mask); 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_cistatic ssize_t ap_interrupts_show(const struct bus_type *bus, char *buf) 125362306a36Sopenharmony_ci{ 125462306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", ap_irq_flag ? 1 : 0); 125562306a36Sopenharmony_ci} 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_cistatic BUS_ATTR_RO(ap_interrupts); 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_cistatic ssize_t config_time_show(const struct bus_type *bus, char *buf) 126062306a36Sopenharmony_ci{ 126162306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", ap_config_time); 126262306a36Sopenharmony_ci} 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_cistatic ssize_t config_time_store(const struct bus_type *bus, 126562306a36Sopenharmony_ci const char *buf, size_t count) 126662306a36Sopenharmony_ci{ 126762306a36Sopenharmony_ci int time; 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci if (sscanf(buf, "%d\n", &time) != 1 || time < 5 || time > 120) 127062306a36Sopenharmony_ci return -EINVAL; 127162306a36Sopenharmony_ci ap_config_time = time; 127262306a36Sopenharmony_ci mod_timer(&ap_config_timer, jiffies + ap_config_time * HZ); 127362306a36Sopenharmony_ci return count; 127462306a36Sopenharmony_ci} 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_cistatic BUS_ATTR_RW(config_time); 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_cistatic ssize_t poll_thread_show(const struct bus_type *bus, char *buf) 127962306a36Sopenharmony_ci{ 128062306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", ap_poll_kthread ? 1 : 0); 128162306a36Sopenharmony_ci} 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_cistatic ssize_t poll_thread_store(const struct bus_type *bus, 128462306a36Sopenharmony_ci const char *buf, size_t count) 128562306a36Sopenharmony_ci{ 128662306a36Sopenharmony_ci bool value; 128762306a36Sopenharmony_ci int rc; 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci rc = kstrtobool(buf, &value); 129062306a36Sopenharmony_ci if (rc) 129162306a36Sopenharmony_ci return rc; 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci if (value) { 129462306a36Sopenharmony_ci rc = ap_poll_thread_start(); 129562306a36Sopenharmony_ci if (rc) 129662306a36Sopenharmony_ci count = rc; 129762306a36Sopenharmony_ci } else { 129862306a36Sopenharmony_ci ap_poll_thread_stop(); 129962306a36Sopenharmony_ci } 130062306a36Sopenharmony_ci return count; 130162306a36Sopenharmony_ci} 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_cistatic BUS_ATTR_RW(poll_thread); 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_cistatic ssize_t poll_timeout_show(const struct bus_type *bus, char *buf) 130662306a36Sopenharmony_ci{ 130762306a36Sopenharmony_ci return sysfs_emit(buf, "%lu\n", poll_high_timeout); 130862306a36Sopenharmony_ci} 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_cistatic ssize_t poll_timeout_store(const struct bus_type *bus, const char *buf, 131162306a36Sopenharmony_ci size_t count) 131262306a36Sopenharmony_ci{ 131362306a36Sopenharmony_ci unsigned long value; 131462306a36Sopenharmony_ci ktime_t hr_time; 131562306a36Sopenharmony_ci int rc; 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci rc = kstrtoul(buf, 0, &value); 131862306a36Sopenharmony_ci if (rc) 131962306a36Sopenharmony_ci return rc; 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci /* 120 seconds = maximum poll interval */ 132262306a36Sopenharmony_ci if (value > 120000000000UL) 132362306a36Sopenharmony_ci return -EINVAL; 132462306a36Sopenharmony_ci poll_high_timeout = value; 132562306a36Sopenharmony_ci hr_time = poll_high_timeout; 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci spin_lock_bh(&ap_poll_timer_lock); 132862306a36Sopenharmony_ci hrtimer_cancel(&ap_poll_timer); 132962306a36Sopenharmony_ci hrtimer_set_expires(&ap_poll_timer, hr_time); 133062306a36Sopenharmony_ci hrtimer_start_expires(&ap_poll_timer, HRTIMER_MODE_ABS); 133162306a36Sopenharmony_ci spin_unlock_bh(&ap_poll_timer_lock); 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci return count; 133462306a36Sopenharmony_ci} 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_cistatic BUS_ATTR_RW(poll_timeout); 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_cistatic ssize_t ap_max_domain_id_show(const struct bus_type *bus, char *buf) 133962306a36Sopenharmony_ci{ 134062306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", ap_max_domain_id); 134162306a36Sopenharmony_ci} 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_cistatic BUS_ATTR_RO(ap_max_domain_id); 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_cistatic ssize_t ap_max_adapter_id_show(const struct bus_type *bus, char *buf) 134662306a36Sopenharmony_ci{ 134762306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", ap_max_adapter_id); 134862306a36Sopenharmony_ci} 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_cistatic BUS_ATTR_RO(ap_max_adapter_id); 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_cistatic ssize_t apmask_show(const struct bus_type *bus, char *buf) 135362306a36Sopenharmony_ci{ 135462306a36Sopenharmony_ci int rc; 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_ci if (mutex_lock_interruptible(&ap_perms_mutex)) 135762306a36Sopenharmony_ci return -ERESTARTSYS; 135862306a36Sopenharmony_ci rc = sysfs_emit(buf, "0x%016lx%016lx%016lx%016lx\n", 135962306a36Sopenharmony_ci ap_perms.apm[0], ap_perms.apm[1], 136062306a36Sopenharmony_ci ap_perms.apm[2], ap_perms.apm[3]); 136162306a36Sopenharmony_ci mutex_unlock(&ap_perms_mutex); 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci return rc; 136462306a36Sopenharmony_ci} 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_cistatic int __verify_card_reservations(struct device_driver *drv, void *data) 136762306a36Sopenharmony_ci{ 136862306a36Sopenharmony_ci int rc = 0; 136962306a36Sopenharmony_ci struct ap_driver *ap_drv = to_ap_drv(drv); 137062306a36Sopenharmony_ci unsigned long *newapm = (unsigned long *)data; 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci /* 137362306a36Sopenharmony_ci * increase the driver's module refcounter to be sure it is not 137462306a36Sopenharmony_ci * going away when we invoke the callback function. 137562306a36Sopenharmony_ci */ 137662306a36Sopenharmony_ci if (!try_module_get(drv->owner)) 137762306a36Sopenharmony_ci return 0; 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci if (ap_drv->in_use) { 138062306a36Sopenharmony_ci rc = ap_drv->in_use(newapm, ap_perms.aqm); 138162306a36Sopenharmony_ci if (rc) 138262306a36Sopenharmony_ci rc = -EBUSY; 138362306a36Sopenharmony_ci } 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_ci /* release the driver's module */ 138662306a36Sopenharmony_ci module_put(drv->owner); 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci return rc; 138962306a36Sopenharmony_ci} 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_cistatic int apmask_commit(unsigned long *newapm) 139262306a36Sopenharmony_ci{ 139362306a36Sopenharmony_ci int rc; 139462306a36Sopenharmony_ci unsigned long reserved[BITS_TO_LONGS(AP_DEVICES)]; 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci /* 139762306a36Sopenharmony_ci * Check if any bits in the apmask have been set which will 139862306a36Sopenharmony_ci * result in queues being removed from non-default drivers 139962306a36Sopenharmony_ci */ 140062306a36Sopenharmony_ci if (bitmap_andnot(reserved, newapm, ap_perms.apm, AP_DEVICES)) { 140162306a36Sopenharmony_ci rc = bus_for_each_drv(&ap_bus_type, NULL, reserved, 140262306a36Sopenharmony_ci __verify_card_reservations); 140362306a36Sopenharmony_ci if (rc) 140462306a36Sopenharmony_ci return rc; 140562306a36Sopenharmony_ci } 140662306a36Sopenharmony_ci 140762306a36Sopenharmony_ci memcpy(ap_perms.apm, newapm, APMASKSIZE); 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci return 0; 141062306a36Sopenharmony_ci} 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_cistatic ssize_t apmask_store(const struct bus_type *bus, const char *buf, 141362306a36Sopenharmony_ci size_t count) 141462306a36Sopenharmony_ci{ 141562306a36Sopenharmony_ci int rc, changes = 0; 141662306a36Sopenharmony_ci DECLARE_BITMAP(newapm, AP_DEVICES); 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_ci if (mutex_lock_interruptible(&ap_perms_mutex)) 141962306a36Sopenharmony_ci return -ERESTARTSYS; 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci rc = ap_parse_bitmap_str(buf, ap_perms.apm, AP_DEVICES, newapm); 142262306a36Sopenharmony_ci if (rc) 142362306a36Sopenharmony_ci goto done; 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci changes = memcmp(ap_perms.apm, newapm, APMASKSIZE); 142662306a36Sopenharmony_ci if (changes) 142762306a36Sopenharmony_ci rc = apmask_commit(newapm); 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_cidone: 143062306a36Sopenharmony_ci mutex_unlock(&ap_perms_mutex); 143162306a36Sopenharmony_ci if (rc) 143262306a36Sopenharmony_ci return rc; 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci if (changes) { 143562306a36Sopenharmony_ci ap_bus_revise_bindings(); 143662306a36Sopenharmony_ci ap_send_mask_changed_uevent(newapm, NULL); 143762306a36Sopenharmony_ci } 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci return count; 144062306a36Sopenharmony_ci} 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_cistatic BUS_ATTR_RW(apmask); 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_cistatic ssize_t aqmask_show(const struct bus_type *bus, char *buf) 144562306a36Sopenharmony_ci{ 144662306a36Sopenharmony_ci int rc; 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci if (mutex_lock_interruptible(&ap_perms_mutex)) 144962306a36Sopenharmony_ci return -ERESTARTSYS; 145062306a36Sopenharmony_ci rc = sysfs_emit(buf, "0x%016lx%016lx%016lx%016lx\n", 145162306a36Sopenharmony_ci ap_perms.aqm[0], ap_perms.aqm[1], 145262306a36Sopenharmony_ci ap_perms.aqm[2], ap_perms.aqm[3]); 145362306a36Sopenharmony_ci mutex_unlock(&ap_perms_mutex); 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci return rc; 145662306a36Sopenharmony_ci} 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_cistatic int __verify_queue_reservations(struct device_driver *drv, void *data) 145962306a36Sopenharmony_ci{ 146062306a36Sopenharmony_ci int rc = 0; 146162306a36Sopenharmony_ci struct ap_driver *ap_drv = to_ap_drv(drv); 146262306a36Sopenharmony_ci unsigned long *newaqm = (unsigned long *)data; 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci /* 146562306a36Sopenharmony_ci * increase the driver's module refcounter to be sure it is not 146662306a36Sopenharmony_ci * going away when we invoke the callback function. 146762306a36Sopenharmony_ci */ 146862306a36Sopenharmony_ci if (!try_module_get(drv->owner)) 146962306a36Sopenharmony_ci return 0; 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci if (ap_drv->in_use) { 147262306a36Sopenharmony_ci rc = ap_drv->in_use(ap_perms.apm, newaqm); 147362306a36Sopenharmony_ci if (rc) 147462306a36Sopenharmony_ci rc = -EBUSY; 147562306a36Sopenharmony_ci } 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci /* release the driver's module */ 147862306a36Sopenharmony_ci module_put(drv->owner); 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci return rc; 148162306a36Sopenharmony_ci} 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_cistatic int aqmask_commit(unsigned long *newaqm) 148462306a36Sopenharmony_ci{ 148562306a36Sopenharmony_ci int rc; 148662306a36Sopenharmony_ci unsigned long reserved[BITS_TO_LONGS(AP_DOMAINS)]; 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci /* 148962306a36Sopenharmony_ci * Check if any bits in the aqmask have been set which will 149062306a36Sopenharmony_ci * result in queues being removed from non-default drivers 149162306a36Sopenharmony_ci */ 149262306a36Sopenharmony_ci if (bitmap_andnot(reserved, newaqm, ap_perms.aqm, AP_DOMAINS)) { 149362306a36Sopenharmony_ci rc = bus_for_each_drv(&ap_bus_type, NULL, reserved, 149462306a36Sopenharmony_ci __verify_queue_reservations); 149562306a36Sopenharmony_ci if (rc) 149662306a36Sopenharmony_ci return rc; 149762306a36Sopenharmony_ci } 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci memcpy(ap_perms.aqm, newaqm, AQMASKSIZE); 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci return 0; 150262306a36Sopenharmony_ci} 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_cistatic ssize_t aqmask_store(const struct bus_type *bus, const char *buf, 150562306a36Sopenharmony_ci size_t count) 150662306a36Sopenharmony_ci{ 150762306a36Sopenharmony_ci int rc, changes = 0; 150862306a36Sopenharmony_ci DECLARE_BITMAP(newaqm, AP_DOMAINS); 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci if (mutex_lock_interruptible(&ap_perms_mutex)) 151162306a36Sopenharmony_ci return -ERESTARTSYS; 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci rc = ap_parse_bitmap_str(buf, ap_perms.aqm, AP_DOMAINS, newaqm); 151462306a36Sopenharmony_ci if (rc) 151562306a36Sopenharmony_ci goto done; 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci changes = memcmp(ap_perms.aqm, newaqm, APMASKSIZE); 151862306a36Sopenharmony_ci if (changes) 151962306a36Sopenharmony_ci rc = aqmask_commit(newaqm); 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_cidone: 152262306a36Sopenharmony_ci mutex_unlock(&ap_perms_mutex); 152362306a36Sopenharmony_ci if (rc) 152462306a36Sopenharmony_ci return rc; 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci if (changes) { 152762306a36Sopenharmony_ci ap_bus_revise_bindings(); 152862306a36Sopenharmony_ci ap_send_mask_changed_uevent(NULL, newaqm); 152962306a36Sopenharmony_ci } 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci return count; 153262306a36Sopenharmony_ci} 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_cistatic BUS_ATTR_RW(aqmask); 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_cistatic ssize_t scans_show(const struct bus_type *bus, char *buf) 153762306a36Sopenharmony_ci{ 153862306a36Sopenharmony_ci return sysfs_emit(buf, "%llu\n", atomic64_read(&ap_scan_bus_count)); 153962306a36Sopenharmony_ci} 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_cistatic ssize_t scans_store(const struct bus_type *bus, const char *buf, 154262306a36Sopenharmony_ci size_t count) 154362306a36Sopenharmony_ci{ 154462306a36Sopenharmony_ci AP_DBF_INFO("%s force AP bus rescan\n", __func__); 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci ap_bus_force_rescan(); 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci return count; 154962306a36Sopenharmony_ci} 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_cistatic BUS_ATTR_RW(scans); 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_cistatic ssize_t bindings_show(const struct bus_type *bus, char *buf) 155462306a36Sopenharmony_ci{ 155562306a36Sopenharmony_ci int rc; 155662306a36Sopenharmony_ci unsigned int apqns, n; 155762306a36Sopenharmony_ci 155862306a36Sopenharmony_ci ap_calc_bound_apqns(&apqns, &n); 155962306a36Sopenharmony_ci if (atomic64_read(&ap_scan_bus_count) >= 1 && n == apqns) 156062306a36Sopenharmony_ci rc = sysfs_emit(buf, "%u/%u (complete)\n", n, apqns); 156162306a36Sopenharmony_ci else 156262306a36Sopenharmony_ci rc = sysfs_emit(buf, "%u/%u\n", n, apqns); 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_ci return rc; 156562306a36Sopenharmony_ci} 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_cistatic BUS_ATTR_RO(bindings); 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_cistatic ssize_t features_show(const struct bus_type *bus, char *buf) 157062306a36Sopenharmony_ci{ 157162306a36Sopenharmony_ci int n = 0; 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci if (!ap_qci_info) /* QCI not supported */ 157462306a36Sopenharmony_ci return sysfs_emit(buf, "-\n"); 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci if (ap_qci_info->apsc) 157762306a36Sopenharmony_ci n += sysfs_emit_at(buf, n, "APSC "); 157862306a36Sopenharmony_ci if (ap_qci_info->apxa) 157962306a36Sopenharmony_ci n += sysfs_emit_at(buf, n, "APXA "); 158062306a36Sopenharmony_ci if (ap_qci_info->qact) 158162306a36Sopenharmony_ci n += sysfs_emit_at(buf, n, "QACT "); 158262306a36Sopenharmony_ci if (ap_qci_info->rc8a) 158362306a36Sopenharmony_ci n += sysfs_emit_at(buf, n, "RC8A "); 158462306a36Sopenharmony_ci if (ap_qci_info->apsb) 158562306a36Sopenharmony_ci n += sysfs_emit_at(buf, n, "APSB "); 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ci sysfs_emit_at(buf, n == 0 ? 0 : n - 1, "\n"); 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci return n; 159062306a36Sopenharmony_ci} 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_cistatic BUS_ATTR_RO(features); 159362306a36Sopenharmony_ci 159462306a36Sopenharmony_cistatic struct attribute *ap_bus_attrs[] = { 159562306a36Sopenharmony_ci &bus_attr_ap_domain.attr, 159662306a36Sopenharmony_ci &bus_attr_ap_control_domain_mask.attr, 159762306a36Sopenharmony_ci &bus_attr_ap_usage_domain_mask.attr, 159862306a36Sopenharmony_ci &bus_attr_ap_adapter_mask.attr, 159962306a36Sopenharmony_ci &bus_attr_config_time.attr, 160062306a36Sopenharmony_ci &bus_attr_poll_thread.attr, 160162306a36Sopenharmony_ci &bus_attr_ap_interrupts.attr, 160262306a36Sopenharmony_ci &bus_attr_poll_timeout.attr, 160362306a36Sopenharmony_ci &bus_attr_ap_max_domain_id.attr, 160462306a36Sopenharmony_ci &bus_attr_ap_max_adapter_id.attr, 160562306a36Sopenharmony_ci &bus_attr_apmask.attr, 160662306a36Sopenharmony_ci &bus_attr_aqmask.attr, 160762306a36Sopenharmony_ci &bus_attr_scans.attr, 160862306a36Sopenharmony_ci &bus_attr_bindings.attr, 160962306a36Sopenharmony_ci &bus_attr_features.attr, 161062306a36Sopenharmony_ci NULL, 161162306a36Sopenharmony_ci}; 161262306a36Sopenharmony_ciATTRIBUTE_GROUPS(ap_bus); 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_cistatic struct bus_type ap_bus_type = { 161562306a36Sopenharmony_ci .name = "ap", 161662306a36Sopenharmony_ci .bus_groups = ap_bus_groups, 161762306a36Sopenharmony_ci .match = &ap_bus_match, 161862306a36Sopenharmony_ci .uevent = &ap_uevent, 161962306a36Sopenharmony_ci .probe = ap_device_probe, 162062306a36Sopenharmony_ci .remove = ap_device_remove, 162162306a36Sopenharmony_ci}; 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ci/** 162462306a36Sopenharmony_ci * ap_select_domain(): Select an AP domain if possible and we haven't 162562306a36Sopenharmony_ci * already done so before. 162662306a36Sopenharmony_ci */ 162762306a36Sopenharmony_cistatic void ap_select_domain(void) 162862306a36Sopenharmony_ci{ 162962306a36Sopenharmony_ci struct ap_queue_status status; 163062306a36Sopenharmony_ci int card, dom; 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_ci /* 163362306a36Sopenharmony_ci * Choose the default domain. Either the one specified with 163462306a36Sopenharmony_ci * the "domain=" parameter or the first domain with at least 163562306a36Sopenharmony_ci * one valid APQN. 163662306a36Sopenharmony_ci */ 163762306a36Sopenharmony_ci spin_lock_bh(&ap_domain_lock); 163862306a36Sopenharmony_ci if (ap_domain_index >= 0) { 163962306a36Sopenharmony_ci /* Domain has already been selected. */ 164062306a36Sopenharmony_ci goto out; 164162306a36Sopenharmony_ci } 164262306a36Sopenharmony_ci for (dom = 0; dom <= ap_max_domain_id; dom++) { 164362306a36Sopenharmony_ci if (!ap_test_config_usage_domain(dom) || 164462306a36Sopenharmony_ci !test_bit_inv(dom, ap_perms.aqm)) 164562306a36Sopenharmony_ci continue; 164662306a36Sopenharmony_ci for (card = 0; card <= ap_max_adapter_id; card++) { 164762306a36Sopenharmony_ci if (!ap_test_config_card_id(card) || 164862306a36Sopenharmony_ci !test_bit_inv(card, ap_perms.apm)) 164962306a36Sopenharmony_ci continue; 165062306a36Sopenharmony_ci status = ap_test_queue(AP_MKQID(card, dom), 165162306a36Sopenharmony_ci ap_apft_available(), 165262306a36Sopenharmony_ci NULL); 165362306a36Sopenharmony_ci if (status.response_code == AP_RESPONSE_NORMAL) 165462306a36Sopenharmony_ci break; 165562306a36Sopenharmony_ci } 165662306a36Sopenharmony_ci if (card <= ap_max_adapter_id) 165762306a36Sopenharmony_ci break; 165862306a36Sopenharmony_ci } 165962306a36Sopenharmony_ci if (dom <= ap_max_domain_id) { 166062306a36Sopenharmony_ci ap_domain_index = dom; 166162306a36Sopenharmony_ci AP_DBF_INFO("%s new default domain is %d\n", 166262306a36Sopenharmony_ci __func__, ap_domain_index); 166362306a36Sopenharmony_ci } 166462306a36Sopenharmony_ciout: 166562306a36Sopenharmony_ci spin_unlock_bh(&ap_domain_lock); 166662306a36Sopenharmony_ci} 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_ci/* 166962306a36Sopenharmony_ci * This function checks the type and returns either 0 for not 167062306a36Sopenharmony_ci * supported or the highest compatible type value (which may 167162306a36Sopenharmony_ci * include the input type value). 167262306a36Sopenharmony_ci */ 167362306a36Sopenharmony_cistatic int ap_get_compatible_type(ap_qid_t qid, int rawtype, unsigned int func) 167462306a36Sopenharmony_ci{ 167562306a36Sopenharmony_ci int comp_type = 0; 167662306a36Sopenharmony_ci 167762306a36Sopenharmony_ci /* < CEX4 is not supported */ 167862306a36Sopenharmony_ci if (rawtype < AP_DEVICE_TYPE_CEX4) { 167962306a36Sopenharmony_ci AP_DBF_WARN("%s queue=%02x.%04x unsupported type %d\n", 168062306a36Sopenharmony_ci __func__, AP_QID_CARD(qid), 168162306a36Sopenharmony_ci AP_QID_QUEUE(qid), rawtype); 168262306a36Sopenharmony_ci return 0; 168362306a36Sopenharmony_ci } 168462306a36Sopenharmony_ci /* up to CEX8 known and fully supported */ 168562306a36Sopenharmony_ci if (rawtype <= AP_DEVICE_TYPE_CEX8) 168662306a36Sopenharmony_ci return rawtype; 168762306a36Sopenharmony_ci /* 168862306a36Sopenharmony_ci * unknown new type > CEX8, check for compatibility 168962306a36Sopenharmony_ci * to the highest known and supported type which is 169062306a36Sopenharmony_ci * currently CEX8 with the help of the QACT function. 169162306a36Sopenharmony_ci */ 169262306a36Sopenharmony_ci if (ap_qact_available()) { 169362306a36Sopenharmony_ci struct ap_queue_status status; 169462306a36Sopenharmony_ci union ap_qact_ap_info apinfo = {0}; 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci apinfo.mode = (func >> 26) & 0x07; 169762306a36Sopenharmony_ci apinfo.cat = AP_DEVICE_TYPE_CEX8; 169862306a36Sopenharmony_ci status = ap_qact(qid, 0, &apinfo); 169962306a36Sopenharmony_ci if (status.response_code == AP_RESPONSE_NORMAL && 170062306a36Sopenharmony_ci apinfo.cat >= AP_DEVICE_TYPE_CEX4 && 170162306a36Sopenharmony_ci apinfo.cat <= AP_DEVICE_TYPE_CEX8) 170262306a36Sopenharmony_ci comp_type = apinfo.cat; 170362306a36Sopenharmony_ci } 170462306a36Sopenharmony_ci if (!comp_type) 170562306a36Sopenharmony_ci AP_DBF_WARN("%s queue=%02x.%04x unable to map type %d\n", 170662306a36Sopenharmony_ci __func__, AP_QID_CARD(qid), 170762306a36Sopenharmony_ci AP_QID_QUEUE(qid), rawtype); 170862306a36Sopenharmony_ci else if (comp_type != rawtype) 170962306a36Sopenharmony_ci AP_DBF_INFO("%s queue=%02x.%04x map type %d to %d\n", 171062306a36Sopenharmony_ci __func__, AP_QID_CARD(qid), AP_QID_QUEUE(qid), 171162306a36Sopenharmony_ci rawtype, comp_type); 171262306a36Sopenharmony_ci return comp_type; 171362306a36Sopenharmony_ci} 171462306a36Sopenharmony_ci 171562306a36Sopenharmony_ci/* 171662306a36Sopenharmony_ci * Helper function to be used with bus_find_dev 171762306a36Sopenharmony_ci * matches for the card device with the given id 171862306a36Sopenharmony_ci */ 171962306a36Sopenharmony_cistatic int __match_card_device_with_id(struct device *dev, const void *data) 172062306a36Sopenharmony_ci{ 172162306a36Sopenharmony_ci return is_card_dev(dev) && to_ap_card(dev)->id == (int)(long)(void *)data; 172262306a36Sopenharmony_ci} 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci/* 172562306a36Sopenharmony_ci * Helper function to be used with bus_find_dev 172662306a36Sopenharmony_ci * matches for the queue device with a given qid 172762306a36Sopenharmony_ci */ 172862306a36Sopenharmony_cistatic int __match_queue_device_with_qid(struct device *dev, const void *data) 172962306a36Sopenharmony_ci{ 173062306a36Sopenharmony_ci return is_queue_dev(dev) && to_ap_queue(dev)->qid == (int)(long)data; 173162306a36Sopenharmony_ci} 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_ci/* 173462306a36Sopenharmony_ci * Helper function to be used with bus_find_dev 173562306a36Sopenharmony_ci * matches any queue device with given queue id 173662306a36Sopenharmony_ci */ 173762306a36Sopenharmony_cistatic int __match_queue_device_with_queue_id(struct device *dev, const void *data) 173862306a36Sopenharmony_ci{ 173962306a36Sopenharmony_ci return is_queue_dev(dev) && 174062306a36Sopenharmony_ci AP_QID_QUEUE(to_ap_queue(dev)->qid) == (int)(long)data; 174162306a36Sopenharmony_ci} 174262306a36Sopenharmony_ci 174362306a36Sopenharmony_ci/* Helper function for notify_config_changed */ 174462306a36Sopenharmony_cistatic int __drv_notify_config_changed(struct device_driver *drv, void *data) 174562306a36Sopenharmony_ci{ 174662306a36Sopenharmony_ci struct ap_driver *ap_drv = to_ap_drv(drv); 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_ci if (try_module_get(drv->owner)) { 174962306a36Sopenharmony_ci if (ap_drv->on_config_changed) 175062306a36Sopenharmony_ci ap_drv->on_config_changed(ap_qci_info, ap_qci_info_old); 175162306a36Sopenharmony_ci module_put(drv->owner); 175262306a36Sopenharmony_ci } 175362306a36Sopenharmony_ci 175462306a36Sopenharmony_ci return 0; 175562306a36Sopenharmony_ci} 175662306a36Sopenharmony_ci 175762306a36Sopenharmony_ci/* Notify all drivers about an qci config change */ 175862306a36Sopenharmony_cistatic inline void notify_config_changed(void) 175962306a36Sopenharmony_ci{ 176062306a36Sopenharmony_ci bus_for_each_drv(&ap_bus_type, NULL, NULL, 176162306a36Sopenharmony_ci __drv_notify_config_changed); 176262306a36Sopenharmony_ci} 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci/* Helper function for notify_scan_complete */ 176562306a36Sopenharmony_cistatic int __drv_notify_scan_complete(struct device_driver *drv, void *data) 176662306a36Sopenharmony_ci{ 176762306a36Sopenharmony_ci struct ap_driver *ap_drv = to_ap_drv(drv); 176862306a36Sopenharmony_ci 176962306a36Sopenharmony_ci if (try_module_get(drv->owner)) { 177062306a36Sopenharmony_ci if (ap_drv->on_scan_complete) 177162306a36Sopenharmony_ci ap_drv->on_scan_complete(ap_qci_info, 177262306a36Sopenharmony_ci ap_qci_info_old); 177362306a36Sopenharmony_ci module_put(drv->owner); 177462306a36Sopenharmony_ci } 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci return 0; 177762306a36Sopenharmony_ci} 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci/* Notify all drivers about bus scan complete */ 178062306a36Sopenharmony_cistatic inline void notify_scan_complete(void) 178162306a36Sopenharmony_ci{ 178262306a36Sopenharmony_ci bus_for_each_drv(&ap_bus_type, NULL, NULL, 178362306a36Sopenharmony_ci __drv_notify_scan_complete); 178462306a36Sopenharmony_ci} 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_ci/* 178762306a36Sopenharmony_ci * Helper function for ap_scan_bus(). 178862306a36Sopenharmony_ci * Remove card device and associated queue devices. 178962306a36Sopenharmony_ci */ 179062306a36Sopenharmony_cistatic inline void ap_scan_rm_card_dev_and_queue_devs(struct ap_card *ac) 179162306a36Sopenharmony_ci{ 179262306a36Sopenharmony_ci bus_for_each_dev(&ap_bus_type, NULL, 179362306a36Sopenharmony_ci (void *)(long)ac->id, 179462306a36Sopenharmony_ci __ap_queue_devices_with_id_unregister); 179562306a36Sopenharmony_ci device_unregister(&ac->ap_dev.device); 179662306a36Sopenharmony_ci} 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_ci/* 179962306a36Sopenharmony_ci * Helper function for ap_scan_bus(). 180062306a36Sopenharmony_ci * Does the scan bus job for all the domains within 180162306a36Sopenharmony_ci * a valid adapter given by an ap_card ptr. 180262306a36Sopenharmony_ci */ 180362306a36Sopenharmony_cistatic inline void ap_scan_domains(struct ap_card *ac) 180462306a36Sopenharmony_ci{ 180562306a36Sopenharmony_ci int rc, dom, depth, type, ml; 180662306a36Sopenharmony_ci bool decfg, chkstop; 180762306a36Sopenharmony_ci struct ap_queue *aq; 180862306a36Sopenharmony_ci struct device *dev; 180962306a36Sopenharmony_ci unsigned int func; 181062306a36Sopenharmony_ci ap_qid_t qid; 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_ci /* 181362306a36Sopenharmony_ci * Go through the configuration for the domains and compare them 181462306a36Sopenharmony_ci * to the existing queue devices. Also take care of the config 181562306a36Sopenharmony_ci * and error state for the queue devices. 181662306a36Sopenharmony_ci */ 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci for (dom = 0; dom <= ap_max_domain_id; dom++) { 181962306a36Sopenharmony_ci qid = AP_MKQID(ac->id, dom); 182062306a36Sopenharmony_ci dev = bus_find_device(&ap_bus_type, NULL, 182162306a36Sopenharmony_ci (void *)(long)qid, 182262306a36Sopenharmony_ci __match_queue_device_with_qid); 182362306a36Sopenharmony_ci aq = dev ? to_ap_queue(dev) : NULL; 182462306a36Sopenharmony_ci if (!ap_test_config_usage_domain(dom)) { 182562306a36Sopenharmony_ci if (dev) { 182662306a36Sopenharmony_ci AP_DBF_INFO("%s(%d,%d) not in config anymore, rm queue dev\n", 182762306a36Sopenharmony_ci __func__, ac->id, dom); 182862306a36Sopenharmony_ci device_unregister(dev); 182962306a36Sopenharmony_ci } 183062306a36Sopenharmony_ci goto put_dev_and_continue; 183162306a36Sopenharmony_ci } 183262306a36Sopenharmony_ci /* domain is valid, get info from this APQN */ 183362306a36Sopenharmony_ci rc = ap_queue_info(qid, &type, &func, &depth, 183462306a36Sopenharmony_ci &ml, &decfg, &chkstop); 183562306a36Sopenharmony_ci switch (rc) { 183662306a36Sopenharmony_ci case -1: 183762306a36Sopenharmony_ci if (dev) { 183862306a36Sopenharmony_ci AP_DBF_INFO("%s(%d,%d) queue_info() failed, rm queue dev\n", 183962306a36Sopenharmony_ci __func__, ac->id, dom); 184062306a36Sopenharmony_ci device_unregister(dev); 184162306a36Sopenharmony_ci } 184262306a36Sopenharmony_ci fallthrough; 184362306a36Sopenharmony_ci case 0: 184462306a36Sopenharmony_ci goto put_dev_and_continue; 184562306a36Sopenharmony_ci default: 184662306a36Sopenharmony_ci break; 184762306a36Sopenharmony_ci } 184862306a36Sopenharmony_ci /* if no queue device exists, create a new one */ 184962306a36Sopenharmony_ci if (!aq) { 185062306a36Sopenharmony_ci aq = ap_queue_create(qid, ac->ap_dev.device_type); 185162306a36Sopenharmony_ci if (!aq) { 185262306a36Sopenharmony_ci AP_DBF_WARN("%s(%d,%d) ap_queue_create() failed\n", 185362306a36Sopenharmony_ci __func__, ac->id, dom); 185462306a36Sopenharmony_ci continue; 185562306a36Sopenharmony_ci } 185662306a36Sopenharmony_ci aq->card = ac; 185762306a36Sopenharmony_ci aq->config = !decfg; 185862306a36Sopenharmony_ci aq->chkstop = chkstop; 185962306a36Sopenharmony_ci dev = &aq->ap_dev.device; 186062306a36Sopenharmony_ci dev->bus = &ap_bus_type; 186162306a36Sopenharmony_ci dev->parent = &ac->ap_dev.device; 186262306a36Sopenharmony_ci dev_set_name(dev, "%02x.%04x", ac->id, dom); 186362306a36Sopenharmony_ci /* register queue device */ 186462306a36Sopenharmony_ci rc = device_register(dev); 186562306a36Sopenharmony_ci if (rc) { 186662306a36Sopenharmony_ci AP_DBF_WARN("%s(%d,%d) device_register() failed\n", 186762306a36Sopenharmony_ci __func__, ac->id, dom); 186862306a36Sopenharmony_ci goto put_dev_and_continue; 186962306a36Sopenharmony_ci } 187062306a36Sopenharmony_ci /* get it and thus adjust reference counter */ 187162306a36Sopenharmony_ci get_device(dev); 187262306a36Sopenharmony_ci if (decfg) { 187362306a36Sopenharmony_ci AP_DBF_INFO("%s(%d,%d) new (decfg) queue dev created\n", 187462306a36Sopenharmony_ci __func__, ac->id, dom); 187562306a36Sopenharmony_ci } else if (chkstop) { 187662306a36Sopenharmony_ci AP_DBF_INFO("%s(%d,%d) new (chkstop) queue dev created\n", 187762306a36Sopenharmony_ci __func__, ac->id, dom); 187862306a36Sopenharmony_ci } else { 187962306a36Sopenharmony_ci /* nudge the queue's state machine */ 188062306a36Sopenharmony_ci ap_queue_init_state(aq); 188162306a36Sopenharmony_ci AP_DBF_INFO("%s(%d,%d) new queue dev created\n", 188262306a36Sopenharmony_ci __func__, ac->id, dom); 188362306a36Sopenharmony_ci } 188462306a36Sopenharmony_ci goto put_dev_and_continue; 188562306a36Sopenharmony_ci } 188662306a36Sopenharmony_ci /* handle state changes on already existing queue device */ 188762306a36Sopenharmony_ci spin_lock_bh(&aq->lock); 188862306a36Sopenharmony_ci /* checkstop state */ 188962306a36Sopenharmony_ci if (chkstop && !aq->chkstop) { 189062306a36Sopenharmony_ci /* checkstop on */ 189162306a36Sopenharmony_ci aq->chkstop = true; 189262306a36Sopenharmony_ci if (aq->dev_state > AP_DEV_STATE_UNINITIATED) { 189362306a36Sopenharmony_ci aq->dev_state = AP_DEV_STATE_ERROR; 189462306a36Sopenharmony_ci aq->last_err_rc = AP_RESPONSE_CHECKSTOPPED; 189562306a36Sopenharmony_ci } 189662306a36Sopenharmony_ci spin_unlock_bh(&aq->lock); 189762306a36Sopenharmony_ci AP_DBF_DBG("%s(%d,%d) queue dev checkstop on\n", 189862306a36Sopenharmony_ci __func__, ac->id, dom); 189962306a36Sopenharmony_ci /* 'receive' pending messages with -EAGAIN */ 190062306a36Sopenharmony_ci ap_flush_queue(aq); 190162306a36Sopenharmony_ci goto put_dev_and_continue; 190262306a36Sopenharmony_ci } else if (!chkstop && aq->chkstop) { 190362306a36Sopenharmony_ci /* checkstop off */ 190462306a36Sopenharmony_ci aq->chkstop = false; 190562306a36Sopenharmony_ci if (aq->dev_state > AP_DEV_STATE_UNINITIATED) 190662306a36Sopenharmony_ci _ap_queue_init_state(aq); 190762306a36Sopenharmony_ci spin_unlock_bh(&aq->lock); 190862306a36Sopenharmony_ci AP_DBF_DBG("%s(%d,%d) queue dev checkstop off\n", 190962306a36Sopenharmony_ci __func__, ac->id, dom); 191062306a36Sopenharmony_ci goto put_dev_and_continue; 191162306a36Sopenharmony_ci } 191262306a36Sopenharmony_ci /* config state change */ 191362306a36Sopenharmony_ci if (decfg && aq->config) { 191462306a36Sopenharmony_ci /* config off this queue device */ 191562306a36Sopenharmony_ci aq->config = false; 191662306a36Sopenharmony_ci if (aq->dev_state > AP_DEV_STATE_UNINITIATED) { 191762306a36Sopenharmony_ci aq->dev_state = AP_DEV_STATE_ERROR; 191862306a36Sopenharmony_ci aq->last_err_rc = AP_RESPONSE_DECONFIGURED; 191962306a36Sopenharmony_ci } 192062306a36Sopenharmony_ci spin_unlock_bh(&aq->lock); 192162306a36Sopenharmony_ci AP_DBF_DBG("%s(%d,%d) queue dev config off\n", 192262306a36Sopenharmony_ci __func__, ac->id, dom); 192362306a36Sopenharmony_ci ap_send_config_uevent(&aq->ap_dev, aq->config); 192462306a36Sopenharmony_ci /* 'receive' pending messages with -EAGAIN */ 192562306a36Sopenharmony_ci ap_flush_queue(aq); 192662306a36Sopenharmony_ci goto put_dev_and_continue; 192762306a36Sopenharmony_ci } else if (!decfg && !aq->config) { 192862306a36Sopenharmony_ci /* config on this queue device */ 192962306a36Sopenharmony_ci aq->config = true; 193062306a36Sopenharmony_ci if (aq->dev_state > AP_DEV_STATE_UNINITIATED) 193162306a36Sopenharmony_ci _ap_queue_init_state(aq); 193262306a36Sopenharmony_ci spin_unlock_bh(&aq->lock); 193362306a36Sopenharmony_ci AP_DBF_DBG("%s(%d,%d) queue dev config on\n", 193462306a36Sopenharmony_ci __func__, ac->id, dom); 193562306a36Sopenharmony_ci ap_send_config_uevent(&aq->ap_dev, aq->config); 193662306a36Sopenharmony_ci goto put_dev_and_continue; 193762306a36Sopenharmony_ci } 193862306a36Sopenharmony_ci /* handle other error states */ 193962306a36Sopenharmony_ci if (!decfg && aq->dev_state == AP_DEV_STATE_ERROR) { 194062306a36Sopenharmony_ci spin_unlock_bh(&aq->lock); 194162306a36Sopenharmony_ci /* 'receive' pending messages with -EAGAIN */ 194262306a36Sopenharmony_ci ap_flush_queue(aq); 194362306a36Sopenharmony_ci /* re-init (with reset) the queue device */ 194462306a36Sopenharmony_ci ap_queue_init_state(aq); 194562306a36Sopenharmony_ci AP_DBF_INFO("%s(%d,%d) queue dev reinit enforced\n", 194662306a36Sopenharmony_ci __func__, ac->id, dom); 194762306a36Sopenharmony_ci goto put_dev_and_continue; 194862306a36Sopenharmony_ci } 194962306a36Sopenharmony_ci spin_unlock_bh(&aq->lock); 195062306a36Sopenharmony_ciput_dev_and_continue: 195162306a36Sopenharmony_ci put_device(dev); 195262306a36Sopenharmony_ci } 195362306a36Sopenharmony_ci} 195462306a36Sopenharmony_ci 195562306a36Sopenharmony_ci/* 195662306a36Sopenharmony_ci * Helper function for ap_scan_bus(). 195762306a36Sopenharmony_ci * Does the scan bus job for the given adapter id. 195862306a36Sopenharmony_ci */ 195962306a36Sopenharmony_cistatic inline void ap_scan_adapter(int ap) 196062306a36Sopenharmony_ci{ 196162306a36Sopenharmony_ci int rc, dom, depth, type, comp_type, ml; 196262306a36Sopenharmony_ci bool decfg, chkstop; 196362306a36Sopenharmony_ci struct ap_card *ac; 196462306a36Sopenharmony_ci struct device *dev; 196562306a36Sopenharmony_ci unsigned int func; 196662306a36Sopenharmony_ci ap_qid_t qid; 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci /* Is there currently a card device for this adapter ? */ 196962306a36Sopenharmony_ci dev = bus_find_device(&ap_bus_type, NULL, 197062306a36Sopenharmony_ci (void *)(long)ap, 197162306a36Sopenharmony_ci __match_card_device_with_id); 197262306a36Sopenharmony_ci ac = dev ? to_ap_card(dev) : NULL; 197362306a36Sopenharmony_ci 197462306a36Sopenharmony_ci /* Adapter not in configuration ? */ 197562306a36Sopenharmony_ci if (!ap_test_config_card_id(ap)) { 197662306a36Sopenharmony_ci if (ac) { 197762306a36Sopenharmony_ci AP_DBF_INFO("%s(%d) ap not in config any more, rm card and queue devs\n", 197862306a36Sopenharmony_ci __func__, ap); 197962306a36Sopenharmony_ci ap_scan_rm_card_dev_and_queue_devs(ac); 198062306a36Sopenharmony_ci put_device(dev); 198162306a36Sopenharmony_ci } 198262306a36Sopenharmony_ci return; 198362306a36Sopenharmony_ci } 198462306a36Sopenharmony_ci 198562306a36Sopenharmony_ci /* 198662306a36Sopenharmony_ci * Adapter ap is valid in the current configuration. So do some checks: 198762306a36Sopenharmony_ci * If no card device exists, build one. If a card device exists, check 198862306a36Sopenharmony_ci * for type and functions changed. For all this we need to find a valid 198962306a36Sopenharmony_ci * APQN first. 199062306a36Sopenharmony_ci */ 199162306a36Sopenharmony_ci 199262306a36Sopenharmony_ci for (dom = 0; dom <= ap_max_domain_id; dom++) 199362306a36Sopenharmony_ci if (ap_test_config_usage_domain(dom)) { 199462306a36Sopenharmony_ci qid = AP_MKQID(ap, dom); 199562306a36Sopenharmony_ci if (ap_queue_info(qid, &type, &func, &depth, 199662306a36Sopenharmony_ci &ml, &decfg, &chkstop) > 0) 199762306a36Sopenharmony_ci break; 199862306a36Sopenharmony_ci } 199962306a36Sopenharmony_ci if (dom > ap_max_domain_id) { 200062306a36Sopenharmony_ci /* Could not find one valid APQN for this adapter */ 200162306a36Sopenharmony_ci if (ac) { 200262306a36Sopenharmony_ci AP_DBF_INFO("%s(%d) no type info (no APQN found), rm card and queue devs\n", 200362306a36Sopenharmony_ci __func__, ap); 200462306a36Sopenharmony_ci ap_scan_rm_card_dev_and_queue_devs(ac); 200562306a36Sopenharmony_ci put_device(dev); 200662306a36Sopenharmony_ci } else { 200762306a36Sopenharmony_ci AP_DBF_DBG("%s(%d) no type info (no APQN found), ignored\n", 200862306a36Sopenharmony_ci __func__, ap); 200962306a36Sopenharmony_ci } 201062306a36Sopenharmony_ci return; 201162306a36Sopenharmony_ci } 201262306a36Sopenharmony_ci if (!type) { 201362306a36Sopenharmony_ci /* No apdater type info available, an unusable adapter */ 201462306a36Sopenharmony_ci if (ac) { 201562306a36Sopenharmony_ci AP_DBF_INFO("%s(%d) no valid type (0) info, rm card and queue devs\n", 201662306a36Sopenharmony_ci __func__, ap); 201762306a36Sopenharmony_ci ap_scan_rm_card_dev_and_queue_devs(ac); 201862306a36Sopenharmony_ci put_device(dev); 201962306a36Sopenharmony_ci } else { 202062306a36Sopenharmony_ci AP_DBF_DBG("%s(%d) no valid type (0) info, ignored\n", 202162306a36Sopenharmony_ci __func__, ap); 202262306a36Sopenharmony_ci } 202362306a36Sopenharmony_ci return; 202462306a36Sopenharmony_ci } 202562306a36Sopenharmony_ci if (ac) { 202662306a36Sopenharmony_ci /* Check APQN against existing card device for changes */ 202762306a36Sopenharmony_ci if (ac->raw_hwtype != type) { 202862306a36Sopenharmony_ci AP_DBF_INFO("%s(%d) hwtype %d changed, rm card and queue devs\n", 202962306a36Sopenharmony_ci __func__, ap, type); 203062306a36Sopenharmony_ci ap_scan_rm_card_dev_and_queue_devs(ac); 203162306a36Sopenharmony_ci put_device(dev); 203262306a36Sopenharmony_ci ac = NULL; 203362306a36Sopenharmony_ci } else if ((ac->functions & TAPQ_CARD_FUNC_CMP_MASK) != 203462306a36Sopenharmony_ci (func & TAPQ_CARD_FUNC_CMP_MASK)) { 203562306a36Sopenharmony_ci AP_DBF_INFO("%s(%d) functions 0x%08x changed, rm card and queue devs\n", 203662306a36Sopenharmony_ci __func__, ap, func); 203762306a36Sopenharmony_ci ap_scan_rm_card_dev_and_queue_devs(ac); 203862306a36Sopenharmony_ci put_device(dev); 203962306a36Sopenharmony_ci ac = NULL; 204062306a36Sopenharmony_ci } else { 204162306a36Sopenharmony_ci /* handle checkstop state change */ 204262306a36Sopenharmony_ci if (chkstop && !ac->chkstop) { 204362306a36Sopenharmony_ci /* checkstop on */ 204462306a36Sopenharmony_ci ac->chkstop = true; 204562306a36Sopenharmony_ci AP_DBF_INFO("%s(%d) card dev checkstop on\n", 204662306a36Sopenharmony_ci __func__, ap); 204762306a36Sopenharmony_ci } else if (!chkstop && ac->chkstop) { 204862306a36Sopenharmony_ci /* checkstop off */ 204962306a36Sopenharmony_ci ac->chkstop = false; 205062306a36Sopenharmony_ci AP_DBF_INFO("%s(%d) card dev checkstop off\n", 205162306a36Sopenharmony_ci __func__, ap); 205262306a36Sopenharmony_ci } 205362306a36Sopenharmony_ci /* handle config state change */ 205462306a36Sopenharmony_ci if (decfg && ac->config) { 205562306a36Sopenharmony_ci ac->config = false; 205662306a36Sopenharmony_ci AP_DBF_INFO("%s(%d) card dev config off\n", 205762306a36Sopenharmony_ci __func__, ap); 205862306a36Sopenharmony_ci ap_send_config_uevent(&ac->ap_dev, ac->config); 205962306a36Sopenharmony_ci } else if (!decfg && !ac->config) { 206062306a36Sopenharmony_ci ac->config = true; 206162306a36Sopenharmony_ci AP_DBF_INFO("%s(%d) card dev config on\n", 206262306a36Sopenharmony_ci __func__, ap); 206362306a36Sopenharmony_ci ap_send_config_uevent(&ac->ap_dev, ac->config); 206462306a36Sopenharmony_ci } 206562306a36Sopenharmony_ci } 206662306a36Sopenharmony_ci } 206762306a36Sopenharmony_ci 206862306a36Sopenharmony_ci if (!ac) { 206962306a36Sopenharmony_ci /* Build a new card device */ 207062306a36Sopenharmony_ci comp_type = ap_get_compatible_type(qid, type, func); 207162306a36Sopenharmony_ci if (!comp_type) { 207262306a36Sopenharmony_ci AP_DBF_WARN("%s(%d) type %d, can't get compatibility type\n", 207362306a36Sopenharmony_ci __func__, ap, type); 207462306a36Sopenharmony_ci return; 207562306a36Sopenharmony_ci } 207662306a36Sopenharmony_ci ac = ap_card_create(ap, depth, type, comp_type, func, ml); 207762306a36Sopenharmony_ci if (!ac) { 207862306a36Sopenharmony_ci AP_DBF_WARN("%s(%d) ap_card_create() failed\n", 207962306a36Sopenharmony_ci __func__, ap); 208062306a36Sopenharmony_ci return; 208162306a36Sopenharmony_ci } 208262306a36Sopenharmony_ci ac->config = !decfg; 208362306a36Sopenharmony_ci ac->chkstop = chkstop; 208462306a36Sopenharmony_ci dev = &ac->ap_dev.device; 208562306a36Sopenharmony_ci dev->bus = &ap_bus_type; 208662306a36Sopenharmony_ci dev->parent = ap_root_device; 208762306a36Sopenharmony_ci dev_set_name(dev, "card%02x", ap); 208862306a36Sopenharmony_ci /* maybe enlarge ap_max_msg_size to support this card */ 208962306a36Sopenharmony_ci if (ac->maxmsgsize > atomic_read(&ap_max_msg_size)) { 209062306a36Sopenharmony_ci atomic_set(&ap_max_msg_size, ac->maxmsgsize); 209162306a36Sopenharmony_ci AP_DBF_INFO("%s(%d) ap_max_msg_size update to %d byte\n", 209262306a36Sopenharmony_ci __func__, ap, 209362306a36Sopenharmony_ci atomic_read(&ap_max_msg_size)); 209462306a36Sopenharmony_ci } 209562306a36Sopenharmony_ci /* Register the new card device with AP bus */ 209662306a36Sopenharmony_ci rc = device_register(dev); 209762306a36Sopenharmony_ci if (rc) { 209862306a36Sopenharmony_ci AP_DBF_WARN("%s(%d) device_register() failed\n", 209962306a36Sopenharmony_ci __func__, ap); 210062306a36Sopenharmony_ci put_device(dev); 210162306a36Sopenharmony_ci return; 210262306a36Sopenharmony_ci } 210362306a36Sopenharmony_ci /* get it and thus adjust reference counter */ 210462306a36Sopenharmony_ci get_device(dev); 210562306a36Sopenharmony_ci if (decfg) 210662306a36Sopenharmony_ci AP_DBF_INFO("%s(%d) new (decfg) card dev type=%d func=0x%08x created\n", 210762306a36Sopenharmony_ci __func__, ap, type, func); 210862306a36Sopenharmony_ci else if (chkstop) 210962306a36Sopenharmony_ci AP_DBF_INFO("%s(%d) new (chkstop) card dev type=%d func=0x%08x created\n", 211062306a36Sopenharmony_ci __func__, ap, type, func); 211162306a36Sopenharmony_ci else 211262306a36Sopenharmony_ci AP_DBF_INFO("%s(%d) new card dev type=%d func=0x%08x created\n", 211362306a36Sopenharmony_ci __func__, ap, type, func); 211462306a36Sopenharmony_ci } 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_ci /* Verify the domains and the queue devices for this card */ 211762306a36Sopenharmony_ci ap_scan_domains(ac); 211862306a36Sopenharmony_ci 211962306a36Sopenharmony_ci /* release the card device */ 212062306a36Sopenharmony_ci put_device(&ac->ap_dev.device); 212162306a36Sopenharmony_ci} 212262306a36Sopenharmony_ci 212362306a36Sopenharmony_ci/** 212462306a36Sopenharmony_ci * ap_get_configuration - get the host AP configuration 212562306a36Sopenharmony_ci * 212662306a36Sopenharmony_ci * Stores the host AP configuration information returned from the previous call 212762306a36Sopenharmony_ci * to Query Configuration Information (QCI), then retrieves and stores the 212862306a36Sopenharmony_ci * current AP configuration returned from QCI. 212962306a36Sopenharmony_ci * 213062306a36Sopenharmony_ci * Return: true if the host AP configuration changed between calls to QCI; 213162306a36Sopenharmony_ci * otherwise, return false. 213262306a36Sopenharmony_ci */ 213362306a36Sopenharmony_cistatic bool ap_get_configuration(void) 213462306a36Sopenharmony_ci{ 213562306a36Sopenharmony_ci if (!ap_qci_info) /* QCI not supported */ 213662306a36Sopenharmony_ci return false; 213762306a36Sopenharmony_ci 213862306a36Sopenharmony_ci memcpy(ap_qci_info_old, ap_qci_info, sizeof(*ap_qci_info)); 213962306a36Sopenharmony_ci ap_fetch_qci_info(ap_qci_info); 214062306a36Sopenharmony_ci 214162306a36Sopenharmony_ci return memcmp(ap_qci_info, ap_qci_info_old, 214262306a36Sopenharmony_ci sizeof(struct ap_config_info)) != 0; 214362306a36Sopenharmony_ci} 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci/** 214662306a36Sopenharmony_ci * ap_scan_bus(): Scan the AP bus for new devices 214762306a36Sopenharmony_ci * Runs periodically, workqueue timer (ap_config_time) 214862306a36Sopenharmony_ci * @unused: Unused pointer. 214962306a36Sopenharmony_ci */ 215062306a36Sopenharmony_cistatic void ap_scan_bus(struct work_struct *unused) 215162306a36Sopenharmony_ci{ 215262306a36Sopenharmony_ci int ap, config_changed = 0; 215362306a36Sopenharmony_ci 215462306a36Sopenharmony_ci /* config change notify */ 215562306a36Sopenharmony_ci config_changed = ap_get_configuration(); 215662306a36Sopenharmony_ci if (config_changed) 215762306a36Sopenharmony_ci notify_config_changed(); 215862306a36Sopenharmony_ci ap_select_domain(); 215962306a36Sopenharmony_ci 216062306a36Sopenharmony_ci AP_DBF_DBG("%s running\n", __func__); 216162306a36Sopenharmony_ci 216262306a36Sopenharmony_ci /* loop over all possible adapters */ 216362306a36Sopenharmony_ci for (ap = 0; ap <= ap_max_adapter_id; ap++) 216462306a36Sopenharmony_ci ap_scan_adapter(ap); 216562306a36Sopenharmony_ci 216662306a36Sopenharmony_ci /* scan complete notify */ 216762306a36Sopenharmony_ci if (config_changed) 216862306a36Sopenharmony_ci notify_scan_complete(); 216962306a36Sopenharmony_ci 217062306a36Sopenharmony_ci /* check if there is at least one queue available with default domain */ 217162306a36Sopenharmony_ci if (ap_domain_index >= 0) { 217262306a36Sopenharmony_ci struct device *dev = 217362306a36Sopenharmony_ci bus_find_device(&ap_bus_type, NULL, 217462306a36Sopenharmony_ci (void *)(long)ap_domain_index, 217562306a36Sopenharmony_ci __match_queue_device_with_queue_id); 217662306a36Sopenharmony_ci if (dev) 217762306a36Sopenharmony_ci put_device(dev); 217862306a36Sopenharmony_ci else 217962306a36Sopenharmony_ci AP_DBF_INFO("%s no queue device with default domain %d available\n", 218062306a36Sopenharmony_ci __func__, ap_domain_index); 218162306a36Sopenharmony_ci } 218262306a36Sopenharmony_ci 218362306a36Sopenharmony_ci if (atomic64_inc_return(&ap_scan_bus_count) == 1) { 218462306a36Sopenharmony_ci AP_DBF_DBG("%s init scan complete\n", __func__); 218562306a36Sopenharmony_ci ap_send_init_scan_done_uevent(); 218662306a36Sopenharmony_ci ap_check_bindings_complete(); 218762306a36Sopenharmony_ci } 218862306a36Sopenharmony_ci 218962306a36Sopenharmony_ci mod_timer(&ap_config_timer, jiffies + ap_config_time * HZ); 219062306a36Sopenharmony_ci} 219162306a36Sopenharmony_ci 219262306a36Sopenharmony_cistatic void ap_config_timeout(struct timer_list *unused) 219362306a36Sopenharmony_ci{ 219462306a36Sopenharmony_ci queue_work(system_long_wq, &ap_scan_work); 219562306a36Sopenharmony_ci} 219662306a36Sopenharmony_ci 219762306a36Sopenharmony_cistatic int __init ap_debug_init(void) 219862306a36Sopenharmony_ci{ 219962306a36Sopenharmony_ci ap_dbf_info = debug_register("ap", 2, 1, 220062306a36Sopenharmony_ci DBF_MAX_SPRINTF_ARGS * sizeof(long)); 220162306a36Sopenharmony_ci debug_register_view(ap_dbf_info, &debug_sprintf_view); 220262306a36Sopenharmony_ci debug_set_level(ap_dbf_info, DBF_ERR); 220362306a36Sopenharmony_ci 220462306a36Sopenharmony_ci return 0; 220562306a36Sopenharmony_ci} 220662306a36Sopenharmony_ci 220762306a36Sopenharmony_cistatic void __init ap_perms_init(void) 220862306a36Sopenharmony_ci{ 220962306a36Sopenharmony_ci /* all resources usable if no kernel parameter string given */ 221062306a36Sopenharmony_ci memset(&ap_perms.ioctlm, 0xFF, sizeof(ap_perms.ioctlm)); 221162306a36Sopenharmony_ci memset(&ap_perms.apm, 0xFF, sizeof(ap_perms.apm)); 221262306a36Sopenharmony_ci memset(&ap_perms.aqm, 0xFF, sizeof(ap_perms.aqm)); 221362306a36Sopenharmony_ci 221462306a36Sopenharmony_ci /* apm kernel parameter string */ 221562306a36Sopenharmony_ci if (apm_str) { 221662306a36Sopenharmony_ci memset(&ap_perms.apm, 0, sizeof(ap_perms.apm)); 221762306a36Sopenharmony_ci ap_parse_mask_str(apm_str, ap_perms.apm, AP_DEVICES, 221862306a36Sopenharmony_ci &ap_perms_mutex); 221962306a36Sopenharmony_ci } 222062306a36Sopenharmony_ci 222162306a36Sopenharmony_ci /* aqm kernel parameter string */ 222262306a36Sopenharmony_ci if (aqm_str) { 222362306a36Sopenharmony_ci memset(&ap_perms.aqm, 0, sizeof(ap_perms.aqm)); 222462306a36Sopenharmony_ci ap_parse_mask_str(aqm_str, ap_perms.aqm, AP_DOMAINS, 222562306a36Sopenharmony_ci &ap_perms_mutex); 222662306a36Sopenharmony_ci } 222762306a36Sopenharmony_ci} 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_ci/** 223062306a36Sopenharmony_ci * ap_module_init(): The module initialization code. 223162306a36Sopenharmony_ci * 223262306a36Sopenharmony_ci * Initializes the module. 223362306a36Sopenharmony_ci */ 223462306a36Sopenharmony_cistatic int __init ap_module_init(void) 223562306a36Sopenharmony_ci{ 223662306a36Sopenharmony_ci int rc; 223762306a36Sopenharmony_ci 223862306a36Sopenharmony_ci rc = ap_debug_init(); 223962306a36Sopenharmony_ci if (rc) 224062306a36Sopenharmony_ci return rc; 224162306a36Sopenharmony_ci 224262306a36Sopenharmony_ci if (!ap_instructions_available()) { 224362306a36Sopenharmony_ci pr_warn("The hardware system does not support AP instructions\n"); 224462306a36Sopenharmony_ci return -ENODEV; 224562306a36Sopenharmony_ci } 224662306a36Sopenharmony_ci 224762306a36Sopenharmony_ci /* init ap_queue hashtable */ 224862306a36Sopenharmony_ci hash_init(ap_queues); 224962306a36Sopenharmony_ci 225062306a36Sopenharmony_ci /* set up the AP permissions (ioctls, ap and aq masks) */ 225162306a36Sopenharmony_ci ap_perms_init(); 225262306a36Sopenharmony_ci 225362306a36Sopenharmony_ci /* Get AP configuration data if available */ 225462306a36Sopenharmony_ci ap_init_qci_info(); 225562306a36Sopenharmony_ci 225662306a36Sopenharmony_ci /* check default domain setting */ 225762306a36Sopenharmony_ci if (ap_domain_index < -1 || ap_domain_index > ap_max_domain_id || 225862306a36Sopenharmony_ci (ap_domain_index >= 0 && 225962306a36Sopenharmony_ci !test_bit_inv(ap_domain_index, ap_perms.aqm))) { 226062306a36Sopenharmony_ci pr_warn("%d is not a valid cryptographic domain\n", 226162306a36Sopenharmony_ci ap_domain_index); 226262306a36Sopenharmony_ci ap_domain_index = -1; 226362306a36Sopenharmony_ci } 226462306a36Sopenharmony_ci 226562306a36Sopenharmony_ci /* enable interrupts if available */ 226662306a36Sopenharmony_ci if (ap_interrupts_available() && ap_useirq) { 226762306a36Sopenharmony_ci rc = register_adapter_interrupt(&ap_airq); 226862306a36Sopenharmony_ci ap_irq_flag = (rc == 0); 226962306a36Sopenharmony_ci } 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_ci /* Create /sys/bus/ap. */ 227262306a36Sopenharmony_ci rc = bus_register(&ap_bus_type); 227362306a36Sopenharmony_ci if (rc) 227462306a36Sopenharmony_ci goto out; 227562306a36Sopenharmony_ci 227662306a36Sopenharmony_ci /* Create /sys/devices/ap. */ 227762306a36Sopenharmony_ci ap_root_device = root_device_register("ap"); 227862306a36Sopenharmony_ci rc = PTR_ERR_OR_ZERO(ap_root_device); 227962306a36Sopenharmony_ci if (rc) 228062306a36Sopenharmony_ci goto out_bus; 228162306a36Sopenharmony_ci ap_root_device->bus = &ap_bus_type; 228262306a36Sopenharmony_ci 228362306a36Sopenharmony_ci /* Setup the AP bus rescan timer. */ 228462306a36Sopenharmony_ci timer_setup(&ap_config_timer, ap_config_timeout, 0); 228562306a36Sopenharmony_ci 228662306a36Sopenharmony_ci /* 228762306a36Sopenharmony_ci * Setup the high resolution poll timer. 228862306a36Sopenharmony_ci * If we are running under z/VM adjust polling to z/VM polling rate. 228962306a36Sopenharmony_ci */ 229062306a36Sopenharmony_ci if (MACHINE_IS_VM) 229162306a36Sopenharmony_ci poll_high_timeout = 1500000; 229262306a36Sopenharmony_ci hrtimer_init(&ap_poll_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); 229362306a36Sopenharmony_ci ap_poll_timer.function = ap_poll_timeout; 229462306a36Sopenharmony_ci 229562306a36Sopenharmony_ci /* Start the low priority AP bus poll thread. */ 229662306a36Sopenharmony_ci if (ap_thread_flag) { 229762306a36Sopenharmony_ci rc = ap_poll_thread_start(); 229862306a36Sopenharmony_ci if (rc) 229962306a36Sopenharmony_ci goto out_work; 230062306a36Sopenharmony_ci } 230162306a36Sopenharmony_ci 230262306a36Sopenharmony_ci queue_work(system_long_wq, &ap_scan_work); 230362306a36Sopenharmony_ci 230462306a36Sopenharmony_ci return 0; 230562306a36Sopenharmony_ci 230662306a36Sopenharmony_ciout_work: 230762306a36Sopenharmony_ci hrtimer_cancel(&ap_poll_timer); 230862306a36Sopenharmony_ci root_device_unregister(ap_root_device); 230962306a36Sopenharmony_ciout_bus: 231062306a36Sopenharmony_ci bus_unregister(&ap_bus_type); 231162306a36Sopenharmony_ciout: 231262306a36Sopenharmony_ci if (ap_irq_flag) 231362306a36Sopenharmony_ci unregister_adapter_interrupt(&ap_airq); 231462306a36Sopenharmony_ci kfree(ap_qci_info); 231562306a36Sopenharmony_ci return rc; 231662306a36Sopenharmony_ci} 231762306a36Sopenharmony_cidevice_initcall(ap_module_init); 2318