| .. | .. |
|---|
| 1 | 1 | /* SPDX-License-Identifier: GPL-2.0+ */ |
|---|
| 2 | 2 | /* |
|---|
| 3 | | - * Copyright IBM Corp. 2006, 2012 |
|---|
| 3 | + * Copyright IBM Corp. 2006, 2019 |
|---|
| 4 | 4 | * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> |
|---|
| 5 | 5 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
|---|
| 6 | 6 | * Ralph Wuerthner <rwuerthn@de.ibm.com> |
|---|
| .. | .. |
|---|
| 15 | 15 | |
|---|
| 16 | 16 | #include <linux/device.h> |
|---|
| 17 | 17 | #include <linux/types.h> |
|---|
| 18 | +#include <linux/hashtable.h> |
|---|
| 18 | 19 | #include <asm/isc.h> |
|---|
| 19 | 20 | #include <asm/ap.h> |
|---|
| 20 | 21 | |
|---|
| 21 | 22 | #define AP_DEVICES 256 /* Number of AP devices. */ |
|---|
| 22 | 23 | #define AP_DOMAINS 256 /* Number of AP domains. */ |
|---|
| 24 | +#define AP_IOCTLS 256 /* Number of ioctls. */ |
|---|
| 23 | 25 | #define AP_RESET_TIMEOUT (HZ*0.7) /* Time in ticks for reset timeouts. */ |
|---|
| 24 | 26 | #define AP_CONFIG_TIME 30 /* Time in seconds between AP bus rescans. */ |
|---|
| 25 | 27 | #define AP_POLL_TIME 1 /* Time in ticks between receive polls. */ |
|---|
| 26 | 28 | |
|---|
| 27 | 29 | extern int ap_domain_index; |
|---|
| 28 | 30 | |
|---|
| 29 | | -extern spinlock_t ap_list_lock; |
|---|
| 30 | | -extern struct list_head ap_card_list; |
|---|
| 31 | +extern DECLARE_HASHTABLE(ap_queues, 8); |
|---|
| 32 | +extern spinlock_t ap_queues_lock; |
|---|
| 31 | 33 | |
|---|
| 32 | 34 | static inline int ap_test_bit(unsigned int *ptr, unsigned int nr) |
|---|
| 33 | 35 | { |
|---|
| .. | .. |
|---|
| 48 | 50 | #define AP_RESPONSE_NO_FIRST_PART 0x13 |
|---|
| 49 | 51 | #define AP_RESPONSE_MESSAGE_TOO_BIG 0x15 |
|---|
| 50 | 52 | #define AP_RESPONSE_REQ_FAC_NOT_INST 0x16 |
|---|
| 53 | +#define AP_RESPONSE_INVALID_DOMAIN 0x42 |
|---|
| 51 | 54 | |
|---|
| 52 | 55 | /* |
|---|
| 53 | 56 | * Known device types |
|---|
| .. | .. |
|---|
| 62 | 65 | #define AP_DEVICE_TYPE_CEX4 10 |
|---|
| 63 | 66 | #define AP_DEVICE_TYPE_CEX5 11 |
|---|
| 64 | 67 | #define AP_DEVICE_TYPE_CEX6 12 |
|---|
| 68 | +#define AP_DEVICE_TYPE_CEX7 13 |
|---|
| 65 | 69 | |
|---|
| 66 | 70 | /* |
|---|
| 67 | 71 | * Known function facilities |
|---|
| .. | .. |
|---|
| 74 | 78 | #define AP_FUNC_APXA 6 |
|---|
| 75 | 79 | |
|---|
| 76 | 80 | /* |
|---|
| 77 | | - * AP interrupt states |
|---|
| 81 | + * AP queue state machine states |
|---|
| 78 | 82 | */ |
|---|
| 79 | | -#define AP_INTR_DISABLED 0 /* AP interrupt disabled */ |
|---|
| 80 | | -#define AP_INTR_ENABLED 1 /* AP interrupt enabled */ |
|---|
| 81 | | - |
|---|
| 82 | | -/* |
|---|
| 83 | | - * AP device states |
|---|
| 84 | | - */ |
|---|
| 85 | | -enum ap_state { |
|---|
| 86 | | - AP_STATE_RESET_START, |
|---|
| 87 | | - AP_STATE_RESET_WAIT, |
|---|
| 88 | | - AP_STATE_SETIRQ_WAIT, |
|---|
| 89 | | - AP_STATE_IDLE, |
|---|
| 90 | | - AP_STATE_WORKING, |
|---|
| 91 | | - AP_STATE_QUEUE_FULL, |
|---|
| 92 | | - AP_STATE_SUSPEND_WAIT, |
|---|
| 93 | | - AP_STATE_BORKED, |
|---|
| 94 | | - NR_AP_STATES |
|---|
| 83 | +enum ap_sm_state { |
|---|
| 84 | + AP_SM_STATE_RESET_START = 0, |
|---|
| 85 | + AP_SM_STATE_RESET_WAIT, |
|---|
| 86 | + AP_SM_STATE_SETIRQ_WAIT, |
|---|
| 87 | + AP_SM_STATE_IDLE, |
|---|
| 88 | + AP_SM_STATE_WORKING, |
|---|
| 89 | + AP_SM_STATE_QUEUE_FULL, |
|---|
| 90 | + NR_AP_SM_STATES |
|---|
| 95 | 91 | }; |
|---|
| 96 | 92 | |
|---|
| 97 | 93 | /* |
|---|
| 98 | | - * AP device events |
|---|
| 94 | + * AP queue state machine events |
|---|
| 99 | 95 | */ |
|---|
| 100 | | -enum ap_event { |
|---|
| 101 | | - AP_EVENT_POLL, |
|---|
| 102 | | - AP_EVENT_TIMEOUT, |
|---|
| 103 | | - NR_AP_EVENTS |
|---|
| 96 | +enum ap_sm_event { |
|---|
| 97 | + AP_SM_EVENT_POLL, |
|---|
| 98 | + AP_SM_EVENT_TIMEOUT, |
|---|
| 99 | + NR_AP_SM_EVENTS |
|---|
| 104 | 100 | }; |
|---|
| 105 | 101 | |
|---|
| 106 | 102 | /* |
|---|
| 107 | | - * AP wait behaviour |
|---|
| 103 | + * AP queue state wait behaviour |
|---|
| 108 | 104 | */ |
|---|
| 109 | | -enum ap_wait { |
|---|
| 110 | | - AP_WAIT_AGAIN, /* retry immediately */ |
|---|
| 111 | | - AP_WAIT_TIMEOUT, /* wait for timeout */ |
|---|
| 112 | | - AP_WAIT_INTERRUPT, /* wait for thin interrupt (if available) */ |
|---|
| 113 | | - AP_WAIT_NONE, /* no wait */ |
|---|
| 114 | | - NR_AP_WAIT |
|---|
| 105 | +enum ap_sm_wait { |
|---|
| 106 | + AP_SM_WAIT_AGAIN = 0, /* retry immediately */ |
|---|
| 107 | + AP_SM_WAIT_TIMEOUT, /* wait for timeout */ |
|---|
| 108 | + AP_SM_WAIT_INTERRUPT, /* wait for thin interrupt (if available) */ |
|---|
| 109 | + AP_SM_WAIT_NONE, /* no wait */ |
|---|
| 110 | + NR_AP_SM_WAIT |
|---|
| 111 | +}; |
|---|
| 112 | + |
|---|
| 113 | +/* |
|---|
| 114 | + * AP queue device states |
|---|
| 115 | + */ |
|---|
| 116 | +enum ap_dev_state { |
|---|
| 117 | + AP_DEV_STATE_UNINITIATED = 0, /* fresh and virgin, not touched */ |
|---|
| 118 | + AP_DEV_STATE_OPERATING, /* queue dev is working normal */ |
|---|
| 119 | + AP_DEV_STATE_SHUTDOWN, /* remove/unbind/shutdown in progress */ |
|---|
| 120 | + AP_DEV_STATE_ERROR, /* device is in error state */ |
|---|
| 121 | + NR_AP_DEV_STATES |
|---|
| 115 | 122 | }; |
|---|
| 116 | 123 | |
|---|
| 117 | 124 | struct ap_device; |
|---|
| .. | .. |
|---|
| 132 | 139 | |
|---|
| 133 | 140 | int (*probe)(struct ap_device *); |
|---|
| 134 | 141 | void (*remove)(struct ap_device *); |
|---|
| 135 | | - void (*suspend)(struct ap_device *); |
|---|
| 136 | | - void (*resume)(struct ap_device *); |
|---|
| 137 | 142 | }; |
|---|
| 138 | 143 | |
|---|
| 139 | 144 | #define to_ap_drv(x) container_of((x), struct ap_driver, driver) |
|---|
| .. | .. |
|---|
| 151 | 156 | |
|---|
| 152 | 157 | struct ap_card { |
|---|
| 153 | 158 | struct ap_device ap_dev; |
|---|
| 154 | | - struct list_head list; /* Private list of AP cards. */ |
|---|
| 155 | | - struct list_head queues; /* List of assoc. AP queues */ |
|---|
| 156 | 159 | void *private; /* ap driver private pointer. */ |
|---|
| 157 | 160 | int raw_hwtype; /* AP raw hardware type. */ |
|---|
| 158 | 161 | unsigned int functions; /* AP device function bitfield. */ |
|---|
| 159 | 162 | int queue_depth; /* AP queue depth.*/ |
|---|
| 160 | 163 | int id; /* AP card number. */ |
|---|
| 164 | + bool config; /* configured state */ |
|---|
| 161 | 165 | atomic64_t total_request_count; /* # requests ever for this AP device.*/ |
|---|
| 162 | 166 | }; |
|---|
| 163 | 167 | |
|---|
| .. | .. |
|---|
| 165 | 169 | |
|---|
| 166 | 170 | struct ap_queue { |
|---|
| 167 | 171 | struct ap_device ap_dev; |
|---|
| 168 | | - struct list_head list; /* Private list of AP queues. */ |
|---|
| 172 | + struct hlist_node hnode; /* Node for the ap_queues hashtable */ |
|---|
| 169 | 173 | struct ap_card *card; /* Ptr to assoc. AP card. */ |
|---|
| 170 | 174 | spinlock_t lock; /* Per device lock. */ |
|---|
| 171 | 175 | void *private; /* ap driver private pointer. */ |
|---|
| 176 | + enum ap_dev_state dev_state; /* queue device state */ |
|---|
| 177 | + bool config; /* configured state */ |
|---|
| 172 | 178 | ap_qid_t qid; /* AP queue id. */ |
|---|
| 173 | | - int interrupt; /* indicate if interrupts are enabled */ |
|---|
| 179 | + bool interrupt; /* indicate if interrupts are enabled */ |
|---|
| 174 | 180 | int queue_count; /* # messages currently on AP queue. */ |
|---|
| 175 | | - enum ap_state state; /* State of the AP device. */ |
|---|
| 176 | 181 | int pendingq_count; /* # requests on pendingq list. */ |
|---|
| 177 | 182 | int requestq_count; /* # requests on requestq list. */ |
|---|
| 178 | 183 | u64 total_request_count; /* # requests ever for this AP device.*/ |
|---|
| .. | .. |
|---|
| 181 | 186 | struct list_head pendingq; /* List of message sent to AP queue. */ |
|---|
| 182 | 187 | struct list_head requestq; /* List of message yet to be sent. */ |
|---|
| 183 | 188 | struct ap_message *reply; /* Per device reply message. */ |
|---|
| 189 | + enum ap_sm_state sm_state; /* ap queue state machine state */ |
|---|
| 190 | + int last_err_rc; /* last error state response code */ |
|---|
| 184 | 191 | }; |
|---|
| 185 | 192 | |
|---|
| 186 | 193 | #define to_ap_queue(x) container_of((x), struct ap_queue, ap_dev.device) |
|---|
| 187 | 194 | |
|---|
| 188 | | -typedef enum ap_wait (ap_func_t)(struct ap_queue *queue); |
|---|
| 195 | +typedef enum ap_sm_wait (ap_func_t)(struct ap_queue *queue); |
|---|
| 196 | + |
|---|
| 197 | +/* failure injection cmd struct */ |
|---|
| 198 | +struct ap_fi { |
|---|
| 199 | + union { |
|---|
| 200 | + u16 cmd; /* fi flags + action */ |
|---|
| 201 | + struct { |
|---|
| 202 | + u8 flags; /* fi flags only */ |
|---|
| 203 | + u8 action; /* fi action only */ |
|---|
| 204 | + }; |
|---|
| 205 | + }; |
|---|
| 206 | +}; |
|---|
| 207 | + |
|---|
| 208 | +/* all currently known fi actions */ |
|---|
| 209 | +enum ap_fi_actions { |
|---|
| 210 | + AP_FI_ACTION_CCA_AGENT_FF = 0x01, |
|---|
| 211 | + AP_FI_ACTION_CCA_DOM_INVAL = 0x02, |
|---|
| 212 | + AP_FI_ACTION_NQAP_QID_INVAL = 0x03, |
|---|
| 213 | +}; |
|---|
| 214 | + |
|---|
| 215 | +/* all currently known fi flags */ |
|---|
| 216 | +enum ap_fi_flags { |
|---|
| 217 | + AP_FI_FLAG_NO_RETRY = 0x01, |
|---|
| 218 | + AP_FI_FLAG_TOGGLE_SPECIAL = 0x02, |
|---|
| 219 | +}; |
|---|
| 189 | 220 | |
|---|
| 190 | 221 | struct ap_message { |
|---|
| 191 | 222 | struct list_head list; /* Request queueing. */ |
|---|
| 192 | 223 | unsigned long long psmid; /* Message id. */ |
|---|
| 193 | | - void *message; /* Pointer to message buffer. */ |
|---|
| 194 | | - size_t length; /* Message length. */ |
|---|
| 224 | + void *msg; /* Pointer to message buffer. */ |
|---|
| 225 | + unsigned int len; /* Message length. */ |
|---|
| 226 | + u16 flags; /* Flags, see AP_MSG_FLAG_xxx */ |
|---|
| 227 | + struct ap_fi fi; /* Failure Injection cmd */ |
|---|
| 195 | 228 | int rc; /* Return code for this message */ |
|---|
| 196 | | - |
|---|
| 197 | 229 | void *private; /* ap driver private pointer. */ |
|---|
| 198 | | - unsigned int special:1; /* Used for special commands. */ |
|---|
| 199 | 230 | /* receive is called from tasklet context */ |
|---|
| 200 | 231 | void (*receive)(struct ap_queue *, struct ap_message *, |
|---|
| 201 | 232 | struct ap_message *); |
|---|
| 202 | 233 | }; |
|---|
| 234 | + |
|---|
| 235 | +#define AP_MSG_FLAG_SPECIAL 1 /* flag msg as 'special' with NQAP */ |
|---|
| 203 | 236 | |
|---|
| 204 | 237 | /** |
|---|
| 205 | 238 | * ap_init_message() - Initialize ap_message. |
|---|
| .. | .. |
|---|
| 218 | 251 | */ |
|---|
| 219 | 252 | static inline void ap_release_message(struct ap_message *ap_msg) |
|---|
| 220 | 253 | { |
|---|
| 221 | | - kzfree(ap_msg->message); |
|---|
| 222 | | - kzfree(ap_msg->private); |
|---|
| 254 | + kfree_sensitive(ap_msg->msg); |
|---|
| 255 | + kfree_sensitive(ap_msg->private); |
|---|
| 223 | 256 | } |
|---|
| 224 | | - |
|---|
| 225 | | -#define for_each_ap_card(_ac) \ |
|---|
| 226 | | - list_for_each_entry(_ac, &ap_card_list, list) |
|---|
| 227 | | - |
|---|
| 228 | | -#define for_each_ap_queue(_aq, _ac) \ |
|---|
| 229 | | - list_for_each_entry(_aq, &(_ac)->queues, list) |
|---|
| 230 | 257 | |
|---|
| 231 | 258 | /* |
|---|
| 232 | 259 | * Note: don't use ap_send/ap_recv after using ap_queue_message |
|---|
| .. | .. |
|---|
| 236 | 263 | int ap_send(ap_qid_t, unsigned long long, void *, size_t); |
|---|
| 237 | 264 | int ap_recv(ap_qid_t, unsigned long long *, void *, size_t); |
|---|
| 238 | 265 | |
|---|
| 239 | | -enum ap_wait ap_sm_event(struct ap_queue *aq, enum ap_event event); |
|---|
| 240 | | -enum ap_wait ap_sm_event_loop(struct ap_queue *aq, enum ap_event event); |
|---|
| 266 | +enum ap_sm_wait ap_sm_event(struct ap_queue *aq, enum ap_sm_event event); |
|---|
| 267 | +enum ap_sm_wait ap_sm_event_loop(struct ap_queue *aq, enum ap_sm_event event); |
|---|
| 241 | 268 | |
|---|
| 242 | | -void ap_queue_message(struct ap_queue *aq, struct ap_message *ap_msg); |
|---|
| 269 | +int ap_queue_message(struct ap_queue *aq, struct ap_message *ap_msg); |
|---|
| 243 | 270 | void ap_cancel_message(struct ap_queue *aq, struct ap_message *ap_msg); |
|---|
| 244 | 271 | void ap_flush_queue(struct ap_queue *aq); |
|---|
| 245 | 272 | |
|---|
| 246 | 273 | void *ap_airq_ptr(void); |
|---|
| 247 | | -void ap_wait(enum ap_wait wait); |
|---|
| 274 | +void ap_wait(enum ap_sm_wait wait); |
|---|
| 248 | 275 | void ap_request_timeout(struct timer_list *t); |
|---|
| 249 | 276 | void ap_bus_force_rescan(void); |
|---|
| 250 | 277 | |
|---|
| 278 | +int ap_test_config_usage_domain(unsigned int domain); |
|---|
| 279 | +int ap_test_config_ctrl_domain(unsigned int domain); |
|---|
| 280 | + |
|---|
| 251 | 281 | void ap_queue_init_reply(struct ap_queue *aq, struct ap_message *ap_msg); |
|---|
| 252 | 282 | struct ap_queue *ap_queue_create(ap_qid_t qid, int device_type); |
|---|
| 283 | +void ap_queue_prepare_remove(struct ap_queue *aq); |
|---|
| 253 | 284 | void ap_queue_remove(struct ap_queue *aq); |
|---|
| 254 | | -void ap_queue_suspend(struct ap_device *ap_dev); |
|---|
| 255 | | -void ap_queue_resume(struct ap_device *ap_dev); |
|---|
| 256 | | -void ap_queue_reinit_state(struct ap_queue *aq); |
|---|
| 285 | +void ap_queue_init_state(struct ap_queue *aq); |
|---|
| 257 | 286 | |
|---|
| 258 | 287 | struct ap_card *ap_card_create(int id, int queue_depth, int raw_device_type, |
|---|
| 259 | 288 | int comp_device_type, unsigned int functions); |
|---|
| 289 | + |
|---|
| 290 | +struct ap_perms { |
|---|
| 291 | + unsigned long ioctlm[BITS_TO_LONGS(AP_IOCTLS)]; |
|---|
| 292 | + unsigned long apm[BITS_TO_LONGS(AP_DEVICES)]; |
|---|
| 293 | + unsigned long aqm[BITS_TO_LONGS(AP_DOMAINS)]; |
|---|
| 294 | +}; |
|---|
| 295 | +extern struct ap_perms ap_perms; |
|---|
| 296 | +extern struct mutex ap_perms_mutex; |
|---|
| 297 | + |
|---|
| 298 | +/* |
|---|
| 299 | + * Get ap_queue device for this qid. |
|---|
| 300 | + * Returns ptr to the struct ap_queue device or NULL if there |
|---|
| 301 | + * was no ap_queue device with this qid found. When something is |
|---|
| 302 | + * found, the reference count of the embedded device is increased. |
|---|
| 303 | + * So the caller has to decrease the reference count after use |
|---|
| 304 | + * with a call to put_device(&aq->ap_dev.device). |
|---|
| 305 | + */ |
|---|
| 306 | +struct ap_queue *ap_get_qdev(ap_qid_t qid); |
|---|
| 260 | 307 | |
|---|
| 261 | 308 | /* |
|---|
| 262 | 309 | * check APQN for owned/reserved by ap bus and default driver(s). |
|---|
| .. | .. |
|---|
| 281 | 328 | int ap_apqn_in_matrix_owned_by_def_drv(unsigned long *apm, |
|---|
| 282 | 329 | unsigned long *aqm); |
|---|
| 283 | 330 | |
|---|
| 331 | +/* |
|---|
| 332 | + * ap_parse_mask_str() - helper function to parse a bitmap string |
|---|
| 333 | + * and clear/set the bits in the bitmap accordingly. The string may be |
|---|
| 334 | + * given as absolute value, a hex string like 0x1F2E3D4C5B6A" simple |
|---|
| 335 | + * overwriting the current content of the bitmap. Or as relative string |
|---|
| 336 | + * like "+1-16,-32,-0x40,+128" where only single bits or ranges of |
|---|
| 337 | + * bits are cleared or set. Distinction is done based on the very |
|---|
| 338 | + * first character which may be '+' or '-' for the relative string |
|---|
| 339 | + * and othewise assume to be an absolute value string. If parsing fails |
|---|
| 340 | + * a negative errno value is returned. All arguments and bitmaps are |
|---|
| 341 | + * big endian order. |
|---|
| 342 | + */ |
|---|
| 343 | +int ap_parse_mask_str(const char *str, |
|---|
| 344 | + unsigned long *bitmap, int bits, |
|---|
| 345 | + struct mutex *lock); |
|---|
| 346 | + |
|---|
| 284 | 347 | #endif /* _AP_BUS_H_ */ |
|---|