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

dmaengine: idxd: don't load pasid config until needed

The driver currently programs the system pasid to the WQ preemptively when
system pasid is enabled. Given that a dwq will reprogram the pasid and
possibly a different pasid, the programming is not necessary. The pasid_en
bit can be set for swq as it does not need pasid programming but
needs the pasid_en bit. Remove system pasid programming on device config
write. Add pasid programming for kernel wq type on wq driver enable. The
char dev driver already reprograms the dwq on ->open() call so there's no
change.

Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Link: https://lore.kernel.org/r/164935607115.1660372.6734518676950372366.stgit@djiang5-desk3.ch.intel.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Dave Jiang and committed by
Vinod Koul
3157dd0a 80380f89

+53 -14
+52 -14
drivers/dma/idxd/device.c
··· 299 299 } 300 300 } 301 301 302 - int idxd_wq_set_pasid(struct idxd_wq *wq, int pasid) 302 + static void __idxd_wq_set_priv_locked(struct idxd_wq *wq, int priv) 303 303 { 304 304 struct idxd_device *idxd = wq->idxd; 305 - int rc; 306 305 union wqcfg wqcfg; 307 306 unsigned int offset; 308 307 309 - rc = idxd_wq_disable(wq, false); 310 - if (rc < 0) 311 - return rc; 308 + offset = WQCFG_OFFSET(idxd, wq->id, WQCFG_PRIVL_IDX); 309 + spin_lock(&idxd->dev_lock); 310 + wqcfg.bits[WQCFG_PRIVL_IDX] = ioread32(idxd->reg_base + offset); 311 + wqcfg.priv = priv; 312 + wq->wqcfg->bits[WQCFG_PRIVL_IDX] = wqcfg.bits[WQCFG_PRIVL_IDX]; 313 + iowrite32(wqcfg.bits[WQCFG_PRIVL_IDX], idxd->reg_base + offset); 314 + spin_unlock(&idxd->dev_lock); 315 + } 316 + 317 + static void __idxd_wq_set_pasid_locked(struct idxd_wq *wq, int pasid) 318 + { 319 + struct idxd_device *idxd = wq->idxd; 320 + union wqcfg wqcfg; 321 + unsigned int offset; 312 322 313 323 offset = WQCFG_OFFSET(idxd, wq->id, WQCFG_PASID_IDX); 314 324 spin_lock(&idxd->dev_lock); 315 325 wqcfg.bits[WQCFG_PASID_IDX] = ioread32(idxd->reg_base + offset); 316 326 wqcfg.pasid_en = 1; 317 327 wqcfg.pasid = pasid; 328 + wq->wqcfg->bits[WQCFG_PASID_IDX] = wqcfg.bits[WQCFG_PASID_IDX]; 318 329 iowrite32(wqcfg.bits[WQCFG_PASID_IDX], idxd->reg_base + offset); 319 330 spin_unlock(&idxd->dev_lock); 331 + } 332 + 333 + int idxd_wq_set_pasid(struct idxd_wq *wq, int pasid) 334 + { 335 + int rc; 336 + 337 + rc = idxd_wq_disable(wq, false); 338 + if (rc < 0) 339 + return rc; 340 + 341 + __idxd_wq_set_pasid_locked(wq, pasid); 320 342 321 343 rc = idxd_wq_enable(wq); 322 344 if (rc < 0) ··· 819 797 */ 820 798 for (i = 0; i < WQCFG_STRIDES(idxd); i++) { 821 799 wq_offset = WQCFG_OFFSET(idxd, wq->id, i); 822 - wq->wqcfg->bits[i] = ioread32(idxd->reg_base + wq_offset); 800 + wq->wqcfg->bits[i] |= ioread32(idxd->reg_base + wq_offset); 823 801 } 824 802 825 803 if (wq->size == 0 && wq->type != IDXD_WQT_NONE) ··· 835 813 if (wq_dedicated(wq)) 836 814 wq->wqcfg->mode = 1; 837 815 838 - if (device_pasid_enabled(idxd)) { 839 - wq->wqcfg->pasid_en = 1; 840 - if (wq->type == IDXD_WQT_KERNEL && wq_dedicated(wq)) 841 - wq->wqcfg->pasid = idxd->pasid; 842 - } 843 - 844 816 /* 845 - * Here the priv bit is set depending on the WQ type. priv = 1 if the 817 + * The WQ priv bit is set depending on the WQ type. priv = 1 if the 846 818 * WQ type is kernel to indicate privileged access. This setting only 847 819 * matters for dedicated WQ. According to the DSA spec: 848 820 * If the WQ is in dedicated mode, WQ PASID Enable is 1, and the ··· 846 830 * In the case of a dedicated kernel WQ that is not able to support 847 831 * the PASID cap, then the configuration will be rejected. 848 832 */ 849 - wq->wqcfg->priv = !!(wq->type == IDXD_WQT_KERNEL); 850 833 if (wq_dedicated(wq) && wq->wqcfg->pasid_en && 851 834 !idxd_device_pasid_priv_enabled(idxd) && 852 835 wq->type == IDXD_WQT_KERNEL) { ··· 1276 1261 dev_dbg(dev, "Shared wq and threshold 0.\n"); 1277 1262 goto err; 1278 1263 } 1264 + } 1265 + 1266 + /* 1267 + * In the event that the WQ is configurable for pasid and priv bits. 1268 + * For kernel wq, the driver should setup the pasid, pasid_en, and priv bit. 1269 + * However, for non-kernel wq, the driver should only set the pasid_en bit for 1270 + * shared wq. A dedicated wq that is not 'kernel' type will configure pasid and 1271 + * pasid_en later on so there is no need to setup. 1272 + */ 1273 + if (test_bit(IDXD_FLAG_CONFIGURABLE, &idxd->flags)) { 1274 + int priv = 0; 1275 + 1276 + if (device_pasid_enabled(idxd)) { 1277 + if (is_idxd_wq_kernel(wq) || wq_shared(wq)) { 1278 + u32 pasid = wq_dedicated(wq) ? idxd->pasid : 0; 1279 + 1280 + __idxd_wq_set_pasid_locked(wq, pasid); 1281 + } 1282 + } 1283 + 1284 + if (is_idxd_wq_kernel(wq)) 1285 + priv = 1; 1286 + __idxd_wq_set_priv_locked(wq, priv); 1279 1287 } 1280 1288 1281 1289 rc = 0;
+1
drivers/dma/idxd/registers.h
··· 353 353 } __packed; 354 354 355 355 #define WQCFG_PASID_IDX 2 356 + #define WQCFG_PRIVL_IDX 2 356 357 #define WQCFG_OCCUP_IDX 6 357 358 358 359 #define WQCFG_OCCUP_MASK 0xffff