Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/pseries/vas: Integrate API with open/close windows

This patch adds VAS window allocatioa/close with the corresponding
hcalls. Also changes to integrate with the existing user space VAS
API and provide register/unregister functions to NX pseries driver.

The driver register function is used to create the user space
interface (/dev/crypto/nx-gzip) and unregister to remove this entry.

The user space process opens this device node and makes an ioctl
to allocate VAS window. The close interface is used to deallocate
window.

Signed-off-by: Haren Myneni <haren@linux.ibm.com>
Reviewed-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/e8d956bace3f182c4d2e66e343ff37cb0391d1fd.camel@linux.ibm.com

authored by

Haren Myneni and committed by
Michael Ellerman
b22f2d88 ca77d488

+228
+4
arch/powerpc/include/asm/vas.h
··· 254 254 u64 feat_type; 255 255 }; 256 256 257 + int h_query_vas_capabilities(const u64 hcall, u8 query_type, u64 result); 258 + int vas_register_api_pseries(struct module *mod, 259 + enum vas_cop_type cop_type, const char *name); 260 + void vas_unregister_api_pseries(void); 257 261 #endif 258 262 259 263 /*
+1
arch/powerpc/platforms/pseries/Makefile
··· 30 30 obj-$(CONFIG_FA_DUMP) += rtas-fadump.o 31 31 32 32 obj-$(CONFIG_SUSPEND) += suspend.o 33 + obj-$(CONFIG_PPC_VAS) += vas.o
+223
arch/powerpc/platforms/pseries/vas.c
··· 10 10 #include <linux/export.h> 11 11 #include <linux/types.h> 12 12 #include <linux/delay.h> 13 + #include <linux/slab.h> 13 14 #include <asm/machdep.h> 14 15 #include <asm/hvcall.h> 15 16 #include <asm/plpar_wrappers.h> ··· 26 25 static bool copypaste_feat; 27 26 28 27 static struct vas_caps vascaps[VAS_MAX_FEAT_TYPE]; 28 + static DEFINE_MUTEX(vas_pseries_mutex); 29 29 30 30 static long hcall_return_busy_check(long rc) 31 31 { ··· 153 151 hcall, rc, query_type, result); 154 152 return -EIO; 155 153 } 154 + EXPORT_SYMBOL_GPL(h_query_vas_capabilities); 155 + 156 + /* 157 + * Allocate window and setup IRQ mapping. 158 + */ 159 + static int allocate_setup_window(struct pseries_vas_window *txwin, 160 + u64 *domain, u8 wintype) 161 + { 162 + int rc; 163 + 164 + rc = h_allocate_vas_window(txwin, domain, wintype, DEF_WIN_CREDS); 165 + if (rc) 166 + return rc; 167 + 168 + txwin->vas_win.wcreds_max = DEF_WIN_CREDS; 169 + 170 + return 0; 171 + } 172 + 173 + static struct vas_window *vas_allocate_window(int vas_id, u64 flags, 174 + enum vas_cop_type cop_type) 175 + { 176 + long domain[PLPAR_HCALL9_BUFSIZE] = {VAS_DEFAULT_DOMAIN_ID}; 177 + struct vas_cop_feat_caps *cop_feat_caps; 178 + struct vas_caps *caps; 179 + struct pseries_vas_window *txwin; 180 + int rc; 181 + 182 + txwin = kzalloc(sizeof(*txwin), GFP_KERNEL); 183 + if (!txwin) 184 + return ERR_PTR(-ENOMEM); 185 + 186 + /* 187 + * A VAS window can have many credits which means that many 188 + * requests can be issued simultaneously. But the hypervisor 189 + * restricts one credit per window. 190 + * The hypervisor introduces 2 different types of credits: 191 + * Default credit type (Uses normal priority FIFO): 192 + * A limited number of credits are assigned to partitions 193 + * based on processor entitlement. But these credits may be 194 + * over-committed on a system depends on whether the CPUs 195 + * are in shared or dedicated modes - that is, more requests 196 + * may be issued across the system than NX can service at 197 + * once which can result in paste command failure (RMA_busy). 198 + * Then the process has to resend requests or fall-back to 199 + * SW compression. 200 + * Quality of Service (QoS) credit type (Uses high priority FIFO): 201 + * To avoid NX HW contention, the system admins can assign 202 + * QoS credits for each LPAR so that this partition is 203 + * guaranteed access to NX resources. These credits are 204 + * assigned to partitions via the HMC. 205 + * Refer PAPR for more information. 206 + * 207 + * Allocate window with QoS credits if user requested. Otherwise 208 + * default credits are used. 209 + */ 210 + if (flags & VAS_TX_WIN_FLAG_QOS_CREDIT) 211 + caps = &vascaps[VAS_GZIP_QOS_FEAT_TYPE]; 212 + else 213 + caps = &vascaps[VAS_GZIP_DEF_FEAT_TYPE]; 214 + 215 + cop_feat_caps = &caps->caps; 216 + 217 + if (atomic_inc_return(&cop_feat_caps->used_lpar_creds) > 218 + atomic_read(&cop_feat_caps->target_lpar_creds)) { 219 + pr_err("Credits are not available to allocate window\n"); 220 + rc = -EINVAL; 221 + goto out; 222 + } 223 + 224 + if (vas_id == -1) { 225 + /* 226 + * The user space is requesting to allocate a window on 227 + * a VAS instance where the process is executing. 228 + * On PowerVM, domain values are passed to the hypervisor 229 + * to select VAS instance. Useful if the process is 230 + * affinity to NUMA node. 231 + * The hypervisor selects VAS instance if 232 + * VAS_DEFAULT_DOMAIN_ID (-1) is passed for domain values. 233 + * The h_allocate_vas_window hcall is defined to take a 234 + * domain values as specified by h_home_node_associativity, 235 + * So no unpacking needs to be done. 236 + */ 237 + rc = plpar_hcall9(H_HOME_NODE_ASSOCIATIVITY, domain, 238 + VPHN_FLAG_VCPU, smp_processor_id()); 239 + if (rc != H_SUCCESS) { 240 + pr_err("H_HOME_NODE_ASSOCIATIVITY error: %d\n", rc); 241 + goto out; 242 + } 243 + } 244 + 245 + /* 246 + * Allocate / Deallocate window hcalls and setup / free IRQs 247 + * have to be protected with mutex. 248 + * Open VAS window: Allocate window hcall and setup IRQ 249 + * Close VAS window: Deallocate window hcall and free IRQ 250 + * The hypervisor waits until all NX requests are 251 + * completed before closing the window. So expects OS 252 + * to handle NX faults, means IRQ can be freed only 253 + * after the deallocate window hcall is returned. 254 + * So once the window is closed with deallocate hcall before 255 + * the IRQ is freed, it can be assigned to new allocate 256 + * hcall with the same fault IRQ by the hypervisor. It can 257 + * result in setup IRQ fail for the new window since the 258 + * same fault IRQ is not freed by the OS before. 259 + */ 260 + mutex_lock(&vas_pseries_mutex); 261 + rc = allocate_setup_window(txwin, (u64 *)&domain[0], 262 + cop_feat_caps->win_type); 263 + mutex_unlock(&vas_pseries_mutex); 264 + if (rc) 265 + goto out; 266 + 267 + /* 268 + * Modify window and it is ready to use. 269 + */ 270 + rc = h_modify_vas_window(txwin); 271 + if (!rc) 272 + rc = get_vas_user_win_ref(&txwin->vas_win.task_ref); 273 + if (rc) 274 + goto out_free; 275 + 276 + vas_user_win_add_mm_context(&txwin->vas_win.task_ref); 277 + txwin->win_type = cop_feat_caps->win_type; 278 + mutex_lock(&vas_pseries_mutex); 279 + list_add(&txwin->win_list, &caps->list); 280 + mutex_unlock(&vas_pseries_mutex); 281 + 282 + return &txwin->vas_win; 283 + 284 + out_free: 285 + h_deallocate_vas_window(txwin->vas_win.winid); 286 + out: 287 + atomic_dec(&cop_feat_caps->used_lpar_creds); 288 + kfree(txwin); 289 + return ERR_PTR(rc); 290 + } 291 + 292 + static u64 vas_paste_address(struct vas_window *vwin) 293 + { 294 + struct pseries_vas_window *win; 295 + 296 + win = container_of(vwin, struct pseries_vas_window, vas_win); 297 + return win->win_addr; 298 + } 299 + 300 + static int deallocate_free_window(struct pseries_vas_window *win) 301 + { 302 + int rc = 0; 303 + 304 + rc = h_deallocate_vas_window(win->vas_win.winid); 305 + 306 + return rc; 307 + } 308 + 309 + static int vas_deallocate_window(struct vas_window *vwin) 310 + { 311 + struct pseries_vas_window *win; 312 + struct vas_cop_feat_caps *caps; 313 + int rc = 0; 314 + 315 + if (!vwin) 316 + return -EINVAL; 317 + 318 + win = container_of(vwin, struct pseries_vas_window, vas_win); 319 + 320 + /* Should not happen */ 321 + if (win->win_type >= VAS_MAX_FEAT_TYPE) { 322 + pr_err("Window (%u): Invalid window type %u\n", 323 + vwin->winid, win->win_type); 324 + return -EINVAL; 325 + } 326 + 327 + caps = &vascaps[win->win_type].caps; 328 + mutex_lock(&vas_pseries_mutex); 329 + rc = deallocate_free_window(win); 330 + if (rc) { 331 + mutex_unlock(&vas_pseries_mutex); 332 + return rc; 333 + } 334 + 335 + list_del(&win->win_list); 336 + atomic_dec(&caps->used_lpar_creds); 337 + mutex_unlock(&vas_pseries_mutex); 338 + 339 + put_vas_user_win_ref(&vwin->task_ref); 340 + mm_context_remove_vas_window(vwin->task_ref.mm); 341 + 342 + kfree(win); 343 + return 0; 344 + } 345 + 346 + static const struct vas_user_win_ops vops_pseries = { 347 + .open_win = vas_allocate_window, /* Open and configure window */ 348 + .paste_addr = vas_paste_address, /* To do copy/paste */ 349 + .close_win = vas_deallocate_window, /* Close window */ 350 + }; 351 + 352 + /* 353 + * Supporting only nx-gzip coprocessor type now, but this API code 354 + * extended to other coprocessor types later. 355 + */ 356 + int vas_register_api_pseries(struct module *mod, enum vas_cop_type cop_type, 357 + const char *name) 358 + { 359 + int rc; 360 + 361 + if (!copypaste_feat) 362 + return -ENOTSUPP; 363 + 364 + rc = vas_register_coproc_api(mod, cop_type, name, &vops_pseries); 365 + 366 + return rc; 367 + } 368 + EXPORT_SYMBOL_GPL(vas_register_api_pseries); 369 + 370 + void vas_unregister_api_pseries(void) 371 + { 372 + vas_unregister_coproc_api(); 373 + } 374 + EXPORT_SYMBOL_GPL(vas_unregister_api_pseries); 156 375 157 376 /* 158 377 * Get the specific capabilities based on the feature type.