0001
0002
0003
0004
0005
0006 #include <linux/hugetlb.h>
0007 #include <linux/sched/mm.h>
0008 #include <asm/opal-api.h>
0009 #include <asm/pnv-pci.h>
0010 #include <misc/cxllib.h>
0011
0012 #include "cxl.h"
0013
0014 #define CXL_INVALID_DRA ~0ull
0015 #define CXL_DUMMY_READ_SIZE 128
0016 #define CXL_DUMMY_READ_ALIGN 8
0017 #define CXL_CAPI_WINDOW_START 0x2000000000000ull
0018 #define CXL_CAPI_WINDOW_LOG_SIZE 48
0019 #define CXL_XSL_CONFIG_CURRENT_VERSION CXL_XSL_CONFIG_VERSION1
0020
0021
0022 bool cxllib_slot_is_supported(struct pci_dev *dev, unsigned long flags)
0023 {
0024 int rc;
0025 u32 phb_index;
0026 u64 chip_id, capp_unit_id;
0027
0028
0029 if (flags)
0030 return false;
0031
0032 if (!cpu_has_feature(CPU_FTR_HVMODE))
0033 return false;
0034
0035 if (!cxl_is_power9())
0036 return false;
0037
0038 if (cxl_slot_is_switched(dev))
0039 return false;
0040
0041
0042 rc = cxl_calc_capp_routing(dev, &chip_id, &phb_index, &capp_unit_id);
0043 if (rc)
0044 return false;
0045
0046 return true;
0047 }
0048 EXPORT_SYMBOL_GPL(cxllib_slot_is_supported);
0049
0050 static DEFINE_MUTEX(dra_mutex);
0051 static u64 dummy_read_addr = CXL_INVALID_DRA;
0052
0053 static int allocate_dummy_read_buf(void)
0054 {
0055 u64 buf, vaddr;
0056 size_t buf_size;
0057
0058
0059
0060
0061
0062 buf_size = CXL_DUMMY_READ_SIZE + (1ull << CXL_DUMMY_READ_ALIGN);
0063 buf = (u64) kzalloc(buf_size, GFP_KERNEL);
0064 if (!buf)
0065 return -ENOMEM;
0066
0067 vaddr = (buf + (1ull << CXL_DUMMY_READ_ALIGN) - 1) &
0068 (~0ull << CXL_DUMMY_READ_ALIGN);
0069
0070 WARN((vaddr + CXL_DUMMY_READ_SIZE) > (buf + buf_size),
0071 "Dummy read buffer alignment issue");
0072 dummy_read_addr = virt_to_phys((void *) vaddr);
0073 return 0;
0074 }
0075
0076 int cxllib_get_xsl_config(struct pci_dev *dev, struct cxllib_xsl_config *cfg)
0077 {
0078 int rc;
0079 u32 phb_index;
0080 u64 chip_id, capp_unit_id;
0081
0082 if (!cpu_has_feature(CPU_FTR_HVMODE))
0083 return -EINVAL;
0084
0085 mutex_lock(&dra_mutex);
0086 if (dummy_read_addr == CXL_INVALID_DRA) {
0087 rc = allocate_dummy_read_buf();
0088 if (rc) {
0089 mutex_unlock(&dra_mutex);
0090 return rc;
0091 }
0092 }
0093 mutex_unlock(&dra_mutex);
0094
0095 rc = cxl_calc_capp_routing(dev, &chip_id, &phb_index, &capp_unit_id);
0096 if (rc)
0097 return rc;
0098
0099 rc = cxl_get_xsl9_dsnctl(dev, capp_unit_id, &cfg->dsnctl);
0100 if (rc)
0101 return rc;
0102
0103 cfg->version = CXL_XSL_CONFIG_CURRENT_VERSION;
0104 cfg->log_bar_size = CXL_CAPI_WINDOW_LOG_SIZE;
0105 cfg->bar_addr = CXL_CAPI_WINDOW_START;
0106 cfg->dra = dummy_read_addr;
0107 return 0;
0108 }
0109 EXPORT_SYMBOL_GPL(cxllib_get_xsl_config);
0110
0111 int cxllib_switch_phb_mode(struct pci_dev *dev, enum cxllib_mode mode,
0112 unsigned long flags)
0113 {
0114 int rc = 0;
0115
0116 if (!cpu_has_feature(CPU_FTR_HVMODE))
0117 return -EINVAL;
0118
0119 switch (mode) {
0120 case CXL_MODE_PCI:
0121
0122
0123
0124
0125
0126
0127
0128
0129 rc = pnv_phb_to_cxl_mode(dev, OPAL_PHB_CAPI_MODE_SNOOP_OFF);
0130 if (rc)
0131 rc = -EBUSY;
0132 else
0133 rc = -EPERM;
0134 break;
0135 case CXL_MODE_CXL:
0136
0137 if (flags != CXL_MODE_DMA_TVT1)
0138 return -EINVAL;
0139 rc = pnv_phb_to_cxl_mode(dev, OPAL_PHB_CAPI_MODE_DMA_TVT1);
0140 if (rc)
0141 return rc;
0142 rc = pnv_phb_to_cxl_mode(dev, OPAL_PHB_CAPI_MODE_SNOOP_ON);
0143 break;
0144 default:
0145 rc = -EINVAL;
0146 }
0147 return rc;
0148 }
0149 EXPORT_SYMBOL_GPL(cxllib_switch_phb_mode);
0150
0151
0152
0153
0154
0155
0156
0157
0158 int cxllib_set_device_dma(struct pci_dev *dev, unsigned long flags)
0159 {
0160 int rc;
0161
0162 if (flags)
0163 return -EINVAL;
0164
0165 rc = dma_set_mask(&dev->dev, DMA_BIT_MASK(64));
0166 return rc;
0167 }
0168 EXPORT_SYMBOL_GPL(cxllib_set_device_dma);
0169
0170 int cxllib_get_PE_attributes(struct task_struct *task,
0171 unsigned long translation_mode,
0172 struct cxllib_pe_attributes *attr)
0173 {
0174 if (translation_mode != CXL_TRANSLATED_MODE &&
0175 translation_mode != CXL_REAL_MODE)
0176 return -EINVAL;
0177
0178 attr->sr = cxl_calculate_sr(false,
0179 task == NULL,
0180 translation_mode == CXL_REAL_MODE,
0181 true);
0182 attr->lpid = mfspr(SPRN_LPID);
0183 if (task) {
0184 struct mm_struct *mm = get_task_mm(task);
0185 if (mm == NULL)
0186 return -EINVAL;
0187
0188
0189
0190
0191 attr->pid = mm->context.id;
0192 mmput(mm);
0193 attr->tid = task->thread.tidr;
0194 } else {
0195 attr->pid = 0;
0196 attr->tid = 0;
0197 }
0198 return 0;
0199 }
0200 EXPORT_SYMBOL_GPL(cxllib_get_PE_attributes);
0201
0202 static int get_vma_info(struct mm_struct *mm, u64 addr,
0203 u64 *vma_start, u64 *vma_end,
0204 unsigned long *page_size)
0205 {
0206 struct vm_area_struct *vma = NULL;
0207 int rc = 0;
0208
0209 mmap_read_lock(mm);
0210
0211 vma = find_vma(mm, addr);
0212 if (!vma) {
0213 rc = -EFAULT;
0214 goto out;
0215 }
0216 *page_size = vma_kernel_pagesize(vma);
0217 *vma_start = vma->vm_start;
0218 *vma_end = vma->vm_end;
0219 out:
0220 mmap_read_unlock(mm);
0221 return rc;
0222 }
0223
0224 int cxllib_handle_fault(struct mm_struct *mm, u64 addr, u64 size, u64 flags)
0225 {
0226 int rc;
0227 u64 dar, vma_start, vma_end;
0228 unsigned long page_size;
0229
0230 if (mm == NULL)
0231 return -EFAULT;
0232
0233
0234
0235
0236
0237
0238
0239 rc = get_vma_info(mm, addr, &vma_start, &vma_end, &page_size);
0240 if (rc)
0241 return rc;
0242
0243 for (dar = (addr & ~(page_size - 1)); dar < (addr + size);
0244 dar += page_size) {
0245 if (dar < vma_start || dar >= vma_end) {
0246
0247
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258
0259 rc = get_vma_info(mm, dar, &vma_start, &vma_end,
0260 &page_size);
0261 if (rc)
0262 return rc;
0263 }
0264
0265 rc = cxl_handle_mm_fault(mm, flags, dar);
0266 if (rc)
0267 return -EFAULT;
0268 }
0269 return 0;
0270 }
0271 EXPORT_SYMBOL_GPL(cxllib_handle_fault);