aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorHolger Dengler <hd@linux.vnet.ibm.com>2012-08-28 10:41:50 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2012-09-26 09:44:54 -0400
commit75014550516b147e5f530b84c71496341e036d6f (patch)
treede0993eb3ec2ea2b5ce0953b8a91630685f60fc5 /drivers/s390
parent48a8ca03f8fd49a4d0c0c8843d4f5a7008dc2656 (diff)
s390/ap: configuration information exploitation
Query AP configuration information. Improve performance of AP bus scans by skipping AP device probing, if the AP deviec is not configured. Reviewed-by: Ingo Tuchscherer <ingo.tuchscherer@linux.vnet.ibm.com> Signed-off-by: Holger Dengler <hd@linux.vnet.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/crypto/ap_bus.c121
-rw-r--r--drivers/s390/crypto/ap_bus.h22
2 files changed, 128 insertions, 15 deletions
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index ae258a4b4e5e..047c7327b1b4 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright IBM Corp. 2006 2 * Copyright IBM Corp. 2006, 2012
3 * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> 3 * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
4 * Martin Schwidefsky <schwidefsky@de.ibm.com> 4 * Martin Schwidefsky <schwidefsky@de.ibm.com>
5 * Ralph Wuerthner <rwuerthn@de.ibm.com> 5 * Ralph Wuerthner <rwuerthn@de.ibm.com>
@@ -62,13 +62,14 @@ static void ap_interrupt_handler(void *unused1, void *unused2);
62static void ap_reset(struct ap_device *ap_dev); 62static void ap_reset(struct ap_device *ap_dev);
63static void ap_config_timeout(unsigned long ptr); 63static void ap_config_timeout(unsigned long ptr);
64static int ap_select_domain(void); 64static int ap_select_domain(void);
65static void ap_query_configuration(void);
65 66
66/* 67/*
67 * Module description. 68 * Module description.
68 */ 69 */
69MODULE_AUTHOR("IBM Corporation"); 70MODULE_AUTHOR("IBM Corporation");
70MODULE_DESCRIPTION("Adjunct Processor Bus driver, " 71MODULE_DESCRIPTION("Adjunct Processor Bus driver, " \
71 "Copyright IBM Corp. 2006"); 72 "Copyright IBM Corp. 2006, 2012");
72MODULE_LICENSE("GPL"); 73MODULE_LICENSE("GPL");
73 74
74/* 75/*
@@ -84,6 +85,7 @@ module_param_named(poll_thread, ap_thread_flag, int, 0000);
84MODULE_PARM_DESC(poll_thread, "Turn on/off poll thread, default is 0 (off)."); 85MODULE_PARM_DESC(poll_thread, "Turn on/off poll thread, default is 0 (off).");
85 86
86static struct device *ap_root_device = NULL; 87static struct device *ap_root_device = NULL;
88static struct ap_config_info *ap_configuration;
87static DEFINE_SPINLOCK(ap_device_list_lock); 89static DEFINE_SPINLOCK(ap_device_list_lock);
88static LIST_HEAD(ap_device_list); 90static LIST_HEAD(ap_device_list);
89 91
@@ -158,6 +160,17 @@ static int ap_interrupts_available(void)
158} 160}
159 161
160/** 162/**
163 * ap_configuration_available(): Test if AP configuration
164 * information is available.
165 *
166 * Returns 1 if AP configuration information is available.
167 */
168static int ap_configuration_available(void)
169{
170 return test_facility(2) && test_facility(12);
171}
172
173/**
161 * ap_test_queue(): Test adjunct processor queue. 174 * ap_test_queue(): Test adjunct processor queue.
162 * @qid: The AP queue number 175 * @qid: The AP queue number
163 * @queue_depth: Pointer to queue depth value 176 * @queue_depth: Pointer to queue depth value
@@ -242,6 +255,26 @@ __ap_query_functions(ap_qid_t qid, unsigned int *functions)
242} 255}
243#endif 256#endif
244 257
258#ifdef CONFIG_64BIT
259static inline int __ap_query_configuration(struct ap_config_info *config)
260{
261 register unsigned long reg0 asm ("0") = 0x04000000UL;
262 register unsigned long reg1 asm ("1") = -EINVAL;
263 register unsigned char *reg2 asm ("2") = (unsigned char *)config;
264
265 asm volatile(
266 ".long 0xb2af0000\n" /* PQAP(QCI) */
267 "0: la %1,0\n"
268 "1:\n"
269 EX_TABLE(0b, 1b)
270 : "+d" (reg0), "+d" (reg1), "+d" (reg2)
271 :
272 : "cc");
273
274 return reg1;
275}
276#endif
277
245/** 278/**
246 * ap_query_functions(): Query supported functions. 279 * ap_query_functions(): Query supported functions.
247 * @qid: The AP queue number 280 * @qid: The AP queue number
@@ -305,8 +338,8 @@ int ap_4096_commands_available(ap_qid_t qid)
305 if (ap_query_functions(qid, &functions)) 338 if (ap_query_functions(qid, &functions))
306 return 0; 339 return 0;
307 340
308 return test_ap_facility(functions, 1) && 341 return ap_test_bit(&functions, 1) &&
309 test_ap_facility(functions, 2); 342 ap_test_bit(&functions, 2);
310} 343}
311EXPORT_SYMBOL(ap_4096_commands_available); 344EXPORT_SYMBOL(ap_4096_commands_available);
312 345
@@ -772,6 +805,7 @@ static int ap_bus_resume(struct device *dev)
772 ap_suspend_flag = 0; 805 ap_suspend_flag = 0;
773 if (!ap_interrupts_available()) 806 if (!ap_interrupts_available())
774 ap_interrupt_indicator = NULL; 807 ap_interrupt_indicator = NULL;
808 ap_query_configuration();
775 if (!user_set_domain) { 809 if (!user_set_domain) {
776 ap_domain_index = -1; 810 ap_domain_index = -1;
777 ap_select_domain(); 811 ap_select_domain();
@@ -997,6 +1031,65 @@ static struct bus_attribute *const ap_bus_attrs[] = {
997 NULL, 1031 NULL,
998}; 1032};
999 1033
1034static inline int ap_test_config(unsigned int *field, unsigned int nr)
1035{
1036 if (nr > 0xFFu)
1037 return 0;
1038 return ap_test_bit((field + (nr >> 5)), (nr & 0x1f));
1039}
1040
1041/*
1042 * ap_test_config_card_id(): Test, whether an AP card ID is configured.
1043 * @id AP card ID
1044 *
1045 * Returns 0 if the card is not configured
1046 * 1 if the card is configured or
1047 * if the configuration information is not available
1048 */
1049static inline int ap_test_config_card_id(unsigned int id)
1050{
1051 if (!ap_configuration)
1052 return 1;
1053 return ap_test_config(ap_configuration->apm, id);
1054}
1055
1056/*
1057 * ap_test_config_domain(): Test, whether an AP usage domain is configured.
1058 * @domain AP usage domain ID
1059 *
1060 * Returns 0 if the usage domain is not configured
1061 * 1 if the usage domain is configured or
1062 * if the configuration information is not available
1063 */
1064static inline int ap_test_config_domain(unsigned int domain)
1065{
1066 if (!ap_configuration)
1067 return 1;
1068 return ap_test_config(ap_configuration->aqm, domain);
1069}
1070
1071/**
1072 * ap_query_configuration(): Query AP configuration information.
1073 *
1074 * Query information of installed cards and configured domains from AP.
1075 */
1076static void ap_query_configuration(void)
1077{
1078#ifdef CONFIG_64BIT
1079 if (ap_configuration_available()) {
1080 if (!ap_configuration)
1081 ap_configuration =
1082 kzalloc(sizeof(struct ap_config_info),
1083 GFP_KERNEL);
1084 if (ap_configuration)
1085 __ap_query_configuration(ap_configuration);
1086 } else
1087 ap_configuration = NULL;
1088#else
1089 ap_configuration = NULL;
1090#endif
1091}
1092
1000/** 1093/**
1001 * ap_select_domain(): Select an AP domain. 1094 * ap_select_domain(): Select an AP domain.
1002 * 1095 *
@@ -1005,6 +1098,7 @@ static struct bus_attribute *const ap_bus_attrs[] = {
1005static int ap_select_domain(void) 1098static int ap_select_domain(void)
1006{ 1099{
1007 int queue_depth, device_type, count, max_count, best_domain; 1100 int queue_depth, device_type, count, max_count, best_domain;
1101 ap_qid_t qid;
1008 int rc, i, j; 1102 int rc, i, j;
1009 1103
1010 /* 1104 /*
@@ -1018,9 +1112,13 @@ static int ap_select_domain(void)
1018 best_domain = -1; 1112 best_domain = -1;
1019 max_count = 0; 1113 max_count = 0;
1020 for (i = 0; i < AP_DOMAINS; i++) { 1114 for (i = 0; i < AP_DOMAINS; i++) {
1115 if (!ap_test_config_domain(i))
1116 continue;
1021 count = 0; 1117 count = 0;
1022 for (j = 0; j < AP_DEVICES; j++) { 1118 for (j = 0; j < AP_DEVICES; j++) {
1023 ap_qid_t qid = AP_MKQID(j, i); 1119 if (!ap_test_config_card_id(j))
1120 continue;
1121 qid = AP_MKQID(j, i);
1024 rc = ap_query_queue(qid, &queue_depth, &device_type); 1122 rc = ap_query_queue(qid, &queue_depth, &device_type);
1025 if (rc) 1123 if (rc)
1026 continue; 1124 continue;
@@ -1169,6 +1267,7 @@ static void ap_scan_bus(struct work_struct *unused)
1169 unsigned int device_functions; 1267 unsigned int device_functions;
1170 int rc, i; 1268 int rc, i;
1171 1269
1270 ap_query_configuration();
1172 if (ap_select_domain() != 0) 1271 if (ap_select_domain() != 0)
1173 return; 1272 return;
1174 for (i = 0; i < AP_DEVICES; i++) { 1273 for (i = 0; i < AP_DEVICES; i++) {
@@ -1176,7 +1275,10 @@ static void ap_scan_bus(struct work_struct *unused)
1176 dev = bus_find_device(&ap_bus_type, NULL, 1275 dev = bus_find_device(&ap_bus_type, NULL,
1177 (void *)(unsigned long)qid, 1276 (void *)(unsigned long)qid,
1178 __ap_scan_bus); 1277 __ap_scan_bus);
1179 rc = ap_query_queue(qid, &queue_depth, &device_type); 1278 if (ap_test_config_card_id(i))
1279 rc = ap_query_queue(qid, &queue_depth, &device_type);
1280 else
1281 rc = -ENODEV;
1180 if (dev) { 1282 if (dev) {
1181 if (rc == -EBUSY) { 1283 if (rc == -EBUSY) {
1182 set_current_state(TASK_UNINTERRUPTIBLE); 1284 set_current_state(TASK_UNINTERRUPTIBLE);
@@ -1227,9 +1329,9 @@ static void ap_scan_bus(struct work_struct *unused)
1227 kfree(ap_dev); 1329 kfree(ap_dev);
1228 continue; 1330 continue;
1229 } 1331 }
1230 if (test_ap_facility(device_functions, 3)) 1332 if (ap_test_bit(&device_functions, 3))
1231 ap_dev->device_type = AP_DEVICE_TYPE_CEX3C; 1333 ap_dev->device_type = AP_DEVICE_TYPE_CEX3C;
1232 else if (test_ap_facility(device_functions, 4)) 1334 else if (ap_test_bit(&device_functions, 4))
1233 ap_dev->device_type = AP_DEVICE_TYPE_CEX3A; 1335 ap_dev->device_type = AP_DEVICE_TYPE_CEX3A;
1234 else { 1336 else {
1235 kfree(ap_dev); 1337 kfree(ap_dev);
@@ -1785,6 +1887,7 @@ int __init ap_module_init(void)
1785 goto out_root; 1887 goto out_root;
1786 } 1888 }
1787 1889
1890 ap_query_configuration();
1788 if (ap_select_domain() == 0) 1891 if (ap_select_domain() == 0)
1789 ap_scan_bus(NULL); 1892 ap_scan_bus(NULL);
1790 1893
diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h
index 52d61995af88..5018f66dada5 100644
--- a/drivers/s390/crypto/ap_bus.h
+++ b/drivers/s390/crypto/ap_bus.h
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright IBM Corp. 2006 2 * Copyright IBM Corp. 2006, 2012
3 * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> 3 * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com>
4 * Martin Schwidefsky <schwidefsky@de.ibm.com> 4 * Martin Schwidefsky <schwidefsky@de.ibm.com>
5 * Ralph Wuerthner <rwuerthn@de.ibm.com> 5 * Ralph Wuerthner <rwuerthn@de.ibm.com>
@@ -83,13 +83,12 @@ int ap_queue_status_invalid_test(struct ap_queue_status *status)
83 return !(memcmp(status, &invalid, sizeof(struct ap_queue_status))); 83 return !(memcmp(status, &invalid, sizeof(struct ap_queue_status)));
84} 84}
85 85
86#define MAX_AP_FACILITY 31 86#define AP_MAX_BITS 31
87 87static inline int ap_test_bit(unsigned int *ptr, unsigned int nr)
88static inline int test_ap_facility(unsigned int function, unsigned int nr)
89{ 88{
90 if (nr > MAX_AP_FACILITY) 89 if (nr > AP_MAX_BITS)
91 return 0; 90 return 0;
92 return function & (unsigned int)(0x80000000 >> nr); 91 return (*ptr & (0x80000000u >> nr)) != 0;
93} 92}
94 93
95#define AP_RESPONSE_NORMAL 0x00 94#define AP_RESPONSE_NORMAL 0x00
@@ -183,6 +182,17 @@ struct ap_message {
183 struct ap_message *); 182 struct ap_message *);
184}; 183};
185 184
185struct ap_config_info {
186 unsigned int special_command:1;
187 unsigned int ap_extended:1;
188 unsigned char reserved1:6;
189 unsigned char reserved2[15];
190 unsigned int apm[8]; /* AP ID mask */
191 unsigned int aqm[8]; /* AP queue mask */
192 unsigned int adm[8]; /* AP domain mask */
193 unsigned char reserved4[16];
194} __packed;
195
186#define AP_DEVICE(dt) \ 196#define AP_DEVICE(dt) \
187 .dev_type=(dt), \ 197 .dev_type=(dt), \
188 .match_flags=AP_DEVICE_ID_MATCH_DEVICE_TYPE, 198 .match_flags=AP_DEVICE_ID_MATCH_DEVICE_TYPE,