• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Intel MIC Platform Software Stack (MPSS)
3  *
4  * Copyright(c) 2013 Intel Corporation.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License, version 2, as
8  * published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * General Public License for more details.
14  *
15  * The full GNU General Public License is included in this distribution in
16  * the file called "COPYING".
17  *
18  * Intel MIC Host driver.
19  *
20  */
21 #include <linux/pci.h>
22 
23 #include "../common/mic_dev.h"
24 #include "mic_device.h"
25 #include "mic_smpt.h"
26 
mic_system_page_mask(struct mic_device * mdev)27 static inline u64 mic_system_page_mask(struct mic_device *mdev)
28 {
29 	return (1ULL << mdev->smpt->info.page_shift) - 1ULL;
30 }
31 
mic_sys_addr_to_smpt(struct mic_device * mdev,dma_addr_t pa)32 static inline u8 mic_sys_addr_to_smpt(struct mic_device *mdev, dma_addr_t pa)
33 {
34 	return (pa - mdev->smpt->info.base) >> mdev->smpt->info.page_shift;
35 }
36 
mic_smpt_to_pa(struct mic_device * mdev,u8 index)37 static inline u64 mic_smpt_to_pa(struct mic_device *mdev, u8 index)
38 {
39 	return mdev->smpt->info.base + (index * mdev->smpt->info.page_size);
40 }
41 
mic_smpt_offset(struct mic_device * mdev,dma_addr_t pa)42 static inline u64 mic_smpt_offset(struct mic_device *mdev, dma_addr_t pa)
43 {
44 	return pa & mic_system_page_mask(mdev);
45 }
46 
mic_smpt_align_low(struct mic_device * mdev,dma_addr_t pa)47 static inline u64 mic_smpt_align_low(struct mic_device *mdev, dma_addr_t pa)
48 {
49 	return ALIGN(pa - mic_system_page_mask(mdev),
50 		mdev->smpt->info.page_size);
51 }
52 
mic_smpt_align_high(struct mic_device * mdev,dma_addr_t pa)53 static inline u64 mic_smpt_align_high(struct mic_device *mdev, dma_addr_t pa)
54 {
55 	return ALIGN(pa, mdev->smpt->info.page_size);
56 }
57 
58 /* Total Cumulative system memory accessible by MIC across all SMPT entries */
mic_max_system_memory(struct mic_device * mdev)59 static inline u64 mic_max_system_memory(struct mic_device *mdev)
60 {
61 	return mdev->smpt->info.num_reg * mdev->smpt->info.page_size;
62 }
63 
64 /* Maximum system memory address accessible by MIC */
mic_max_system_addr(struct mic_device * mdev)65 static inline u64 mic_max_system_addr(struct mic_device *mdev)
66 {
67 	return mdev->smpt->info.base + mic_max_system_memory(mdev) - 1ULL;
68 }
69 
70 /* Check if the DMA address is a MIC system memory address */
71 static inline bool
mic_is_system_addr(struct mic_device * mdev,dma_addr_t pa)72 mic_is_system_addr(struct mic_device *mdev, dma_addr_t pa)
73 {
74 	return pa >= mdev->smpt->info.base && pa <= mic_max_system_addr(mdev);
75 }
76 
77 /* Populate an SMPT entry and update the reference counts. */
mic_add_smpt_entry(int spt,s64 * ref,u64 addr,int entries,struct mic_device * mdev)78 static void mic_add_smpt_entry(int spt, s64 *ref, u64 addr,
79 		int entries, struct mic_device *mdev)
80 {
81 	struct mic_smpt_info *smpt_info = mdev->smpt;
82 	int i;
83 
84 	for (i = spt; i < spt + entries; i++,
85 		addr += smpt_info->info.page_size) {
86 		if (!smpt_info->entry[i].ref_count &&
87 		    (smpt_info->entry[i].dma_addr != addr)) {
88 			mdev->smpt_ops->set(mdev, addr, i);
89 			smpt_info->entry[i].dma_addr = addr;
90 		}
91 		smpt_info->entry[i].ref_count += ref[i - spt];
92 	}
93 }
94 
95 /*
96  * Find an available MIC address in MIC SMPT address space
97  * for a given DMA address and size.
98  */
mic_smpt_op(struct mic_device * mdev,u64 dma_addr,int entries,s64 * ref,size_t size)99 static dma_addr_t mic_smpt_op(struct mic_device *mdev, u64 dma_addr,
100 				int entries, s64 *ref, size_t size)
101 {
102 	int spt;
103 	int ae = 0;
104 	int i;
105 	unsigned long flags;
106 	dma_addr_t mic_addr = 0;
107 	dma_addr_t addr = dma_addr;
108 	struct mic_smpt_info *smpt_info = mdev->smpt;
109 
110 	spin_lock_irqsave(&smpt_info->smpt_lock, flags);
111 
112 	/* find existing entries */
113 	for (i = 0; i < smpt_info->info.num_reg; i++) {
114 		if (smpt_info->entry[i].dma_addr == addr) {
115 			ae++;
116 			addr += smpt_info->info.page_size;
117 		} else if (ae) /* cannot find contiguous entries */
118 			goto not_found;
119 
120 		if (ae == entries)
121 			goto found;
122 	}
123 
124 	/* find free entry */
125 	for (ae = 0, i = 0; i < smpt_info->info.num_reg; i++) {
126 		ae = (smpt_info->entry[i].ref_count == 0) ? ae + 1 : 0;
127 		if (ae == entries)
128 			goto found;
129 	}
130 
131 not_found:
132 	spin_unlock_irqrestore(&smpt_info->smpt_lock, flags);
133 	return mic_addr;
134 
135 found:
136 	spt = i - entries + 1;
137 	mic_addr = mic_smpt_to_pa(mdev, spt);
138 	mic_add_smpt_entry(spt, ref, dma_addr, entries, mdev);
139 	smpt_info->map_count++;
140 	smpt_info->ref_count += (s64)size;
141 	spin_unlock_irqrestore(&smpt_info->smpt_lock, flags);
142 	return mic_addr;
143 }
144 
145 /*
146  * Returns number of smpt entries needed for dma_addr to dma_addr + size
147  * also returns the reference count array for each of those entries
148  * and the starting smpt address
149  */
mic_get_smpt_ref_count(struct mic_device * mdev,dma_addr_t dma_addr,size_t size,s64 * ref,u64 * smpt_start)150 static int mic_get_smpt_ref_count(struct mic_device *mdev, dma_addr_t dma_addr,
151 				size_t size, s64 *ref,  u64 *smpt_start)
152 {
153 	u64 start =  dma_addr;
154 	u64 end = dma_addr + size;
155 	int i = 0;
156 
157 	while (start < end) {
158 		ref[i++] = min(mic_smpt_align_high(mdev, start + 1),
159 			end) - start;
160 		start = mic_smpt_align_high(mdev, start + 1);
161 	}
162 
163 	if (smpt_start)
164 		*smpt_start = mic_smpt_align_low(mdev, dma_addr);
165 
166 	return i;
167 }
168 
169 /*
170  * mic_to_dma_addr - Converts a MIC address to a DMA address.
171  *
172  * @mdev: pointer to mic_device instance.
173  * @mic_addr: MIC address.
174  *
175  * returns a DMA address.
176  */
177 static dma_addr_t
mic_to_dma_addr(struct mic_device * mdev,dma_addr_t mic_addr)178 mic_to_dma_addr(struct mic_device *mdev, dma_addr_t mic_addr)
179 {
180 	struct mic_smpt_info *smpt_info = mdev->smpt;
181 	int spt;
182 	dma_addr_t dma_addr;
183 
184 	if (!mic_is_system_addr(mdev, mic_addr)) {
185 		dev_err(mdev->sdev->parent,
186 			"mic_addr is invalid. mic_addr = 0x%llx\n", mic_addr);
187 		return -EINVAL;
188 	}
189 	spt = mic_sys_addr_to_smpt(mdev, mic_addr);
190 	dma_addr = smpt_info->entry[spt].dma_addr +
191 		mic_smpt_offset(mdev, mic_addr);
192 	return dma_addr;
193 }
194 
195 /**
196  * mic_map - Maps a DMA address to a MIC physical address.
197  *
198  * @mdev: pointer to mic_device instance.
199  * @dma_addr: DMA address.
200  * @size: Size of the region to be mapped.
201  *
202  * This API converts the DMA address provided to a DMA address understood
203  * by MIC. Caller should check for errors by calling mic_map_error(..).
204  *
205  * returns DMA address as required by MIC.
206  */
mic_map(struct mic_device * mdev,dma_addr_t dma_addr,size_t size)207 dma_addr_t mic_map(struct mic_device *mdev, dma_addr_t dma_addr, size_t size)
208 {
209 	dma_addr_t mic_addr = 0;
210 	int num_entries;
211 	s64 *ref;
212 	u64 smpt_start;
213 
214 	if (!size || size > mic_max_system_memory(mdev))
215 		return mic_addr;
216 
217 	ref = kmalloc(mdev->smpt->info.num_reg * sizeof(s64), GFP_KERNEL);
218 	if (!ref)
219 		return mic_addr;
220 
221 	num_entries = mic_get_smpt_ref_count(mdev, dma_addr, size,
222 		ref, &smpt_start);
223 
224 	/* Set the smpt table appropriately and get 16G aligned mic address */
225 	mic_addr = mic_smpt_op(mdev, smpt_start, num_entries, ref, size);
226 
227 	kfree(ref);
228 
229 	/*
230 	 * If mic_addr is zero then its an error case
231 	 * since mic_addr can never be zero.
232 	 * else generate mic_addr by adding the 16G offset in dma_addr
233 	 */
234 	if (!mic_addr && MIC_FAMILY_X100 == mdev->family) {
235 		dev_err(mdev->sdev->parent,
236 			"mic_map failed dma_addr 0x%llx size 0x%lx\n",
237 			dma_addr, size);
238 		return mic_addr;
239 	} else {
240 		return mic_addr + mic_smpt_offset(mdev, dma_addr);
241 	}
242 }
243 
244 /**
245  * mic_unmap - Unmaps a MIC physical address.
246  *
247  * @mdev: pointer to mic_device instance.
248  * @mic_addr: MIC physical address.
249  * @size: Size of the region to be unmapped.
250  *
251  * This API unmaps the mappings created by mic_map(..).
252  *
253  * returns None.
254  */
mic_unmap(struct mic_device * mdev,dma_addr_t mic_addr,size_t size)255 void mic_unmap(struct mic_device *mdev, dma_addr_t mic_addr, size_t size)
256 {
257 	struct mic_smpt_info *smpt_info = mdev->smpt;
258 	s64 *ref;
259 	int num_smpt;
260 	int spt;
261 	int i;
262 	unsigned long flags;
263 
264 	if (!size)
265 		return;
266 
267 	if (!mic_is_system_addr(mdev, mic_addr)) {
268 		dev_err(mdev->sdev->parent,
269 			"invalid address: 0x%llx\n", mic_addr);
270 		return;
271 	}
272 
273 	spt = mic_sys_addr_to_smpt(mdev, mic_addr);
274 	ref = kmalloc(mdev->smpt->info.num_reg * sizeof(s64), GFP_KERNEL);
275 	if (!ref)
276 		return;
277 
278 	/* Get number of smpt entries to be mapped, ref count array */
279 	num_smpt = mic_get_smpt_ref_count(mdev, mic_addr, size, ref, NULL);
280 
281 	spin_lock_irqsave(&smpt_info->smpt_lock, flags);
282 	smpt_info->unmap_count++;
283 	smpt_info->ref_count -= (s64)size;
284 
285 	for (i = spt; i < spt + num_smpt; i++) {
286 		smpt_info->entry[i].ref_count -= ref[i - spt];
287 		if (smpt_info->entry[i].ref_count < 0)
288 			dev_warn(mdev->sdev->parent,
289 				 "ref count for entry %d is negative\n", i);
290 	}
291 	spin_unlock_irqrestore(&smpt_info->smpt_lock, flags);
292 	kfree(ref);
293 }
294 
295 /**
296  * mic_map_single - Maps a virtual address to a MIC physical address.
297  *
298  * @mdev: pointer to mic_device instance.
299  * @va: Kernel direct mapped virtual address.
300  * @size: Size of the region to be mapped.
301  *
302  * This API calls pci_map_single(..) for the direct mapped virtual address
303  * and then converts the DMA address provided to a DMA address understood
304  * by MIC. Caller should check for errors by calling mic_map_error(..).
305  *
306  * returns DMA address as required by MIC.
307  */
mic_map_single(struct mic_device * mdev,void * va,size_t size)308 dma_addr_t mic_map_single(struct mic_device *mdev, void *va, size_t size)
309 {
310 	dma_addr_t mic_addr = 0;
311 	struct pci_dev *pdev = container_of(mdev->sdev->parent,
312 		struct pci_dev, dev);
313 	dma_addr_t dma_addr =
314 		pci_map_single(pdev, va, size, PCI_DMA_BIDIRECTIONAL);
315 
316 	if (!pci_dma_mapping_error(pdev, dma_addr)) {
317 		mic_addr = mic_map(mdev, dma_addr, size);
318 		if (!mic_addr) {
319 			dev_err(mdev->sdev->parent,
320 				"mic_map failed dma_addr 0x%llx size 0x%lx\n",
321 				dma_addr, size);
322 			pci_unmap_single(pdev, dma_addr,
323 					 size, PCI_DMA_BIDIRECTIONAL);
324 		}
325 	}
326 	return mic_addr;
327 }
328 
329 /**
330  * mic_unmap_single - Unmaps a MIC physical address.
331  *
332  * @mdev: pointer to mic_device instance.
333  * @mic_addr: MIC physical address.
334  * @size: Size of the region to be unmapped.
335  *
336  * This API unmaps the mappings created by mic_map_single(..).
337  *
338  * returns None.
339  */
340 void
mic_unmap_single(struct mic_device * mdev,dma_addr_t mic_addr,size_t size)341 mic_unmap_single(struct mic_device *mdev, dma_addr_t mic_addr, size_t size)
342 {
343 	struct pci_dev *pdev = container_of(mdev->sdev->parent,
344 		struct pci_dev, dev);
345 	dma_addr_t dma_addr = mic_to_dma_addr(mdev, mic_addr);
346 	mic_unmap(mdev, mic_addr, size);
347 	pci_unmap_single(pdev, dma_addr, size, PCI_DMA_BIDIRECTIONAL);
348 }
349 
350 /**
351  * mic_smpt_init - Initialize MIC System Memory Page Tables.
352  *
353  * @mdev: pointer to mic_device instance.
354  *
355  * returns 0 for success and -errno for error.
356  */
mic_smpt_init(struct mic_device * mdev)357 int mic_smpt_init(struct mic_device *mdev)
358 {
359 	int i, err = 0;
360 	dma_addr_t dma_addr;
361 	struct mic_smpt_info *smpt_info;
362 
363 	mdev->smpt = kmalloc(sizeof(*mdev->smpt), GFP_KERNEL);
364 	if (!mdev->smpt)
365 		return -ENOMEM;
366 
367 	smpt_info = mdev->smpt;
368 	mdev->smpt_ops->init(mdev);
369 	smpt_info->entry = kmalloc_array(smpt_info->info.num_reg,
370 					 sizeof(*smpt_info->entry), GFP_KERNEL);
371 	if (!smpt_info->entry) {
372 		err = -ENOMEM;
373 		goto free_smpt;
374 	}
375 	spin_lock_init(&smpt_info->smpt_lock);
376 	for (i = 0; i < smpt_info->info.num_reg; i++) {
377 		dma_addr = i * smpt_info->info.page_size;
378 		smpt_info->entry[i].dma_addr = dma_addr;
379 		smpt_info->entry[i].ref_count = 0;
380 		mdev->smpt_ops->set(mdev, dma_addr, i);
381 	}
382 	smpt_info->ref_count = 0;
383 	smpt_info->map_count = 0;
384 	smpt_info->unmap_count = 0;
385 	return 0;
386 free_smpt:
387 	kfree(smpt_info);
388 	return err;
389 }
390 
391 /**
392  * mic_smpt_uninit - UnInitialize MIC System Memory Page Tables.
393  *
394  * @mdev: pointer to mic_device instance.
395  *
396  * returns None.
397  */
mic_smpt_uninit(struct mic_device * mdev)398 void mic_smpt_uninit(struct mic_device *mdev)
399 {
400 	struct mic_smpt_info *smpt_info = mdev->smpt;
401 	int i;
402 
403 	dev_dbg(mdev->sdev->parent,
404 		"nodeid %d SMPT ref count %lld map %lld unmap %lld\n",
405 		mdev->id, smpt_info->ref_count,
406 		smpt_info->map_count, smpt_info->unmap_count);
407 
408 	for (i = 0; i < smpt_info->info.num_reg; i++) {
409 		dev_dbg(mdev->sdev->parent,
410 			"SMPT entry[%d] dma_addr = 0x%llx ref_count = %lld\n",
411 			i, smpt_info->entry[i].dma_addr,
412 			smpt_info->entry[i].ref_count);
413 		if (smpt_info->entry[i].ref_count)
414 			dev_warn(mdev->sdev->parent,
415 				 "ref count for entry %d is not zero\n", i);
416 	}
417 	kfree(smpt_info->entry);
418 	kfree(smpt_info);
419 }
420 
421 /**
422  * mic_smpt_restore - Restore MIC System Memory Page Tables.
423  *
424  * @mdev: pointer to mic_device instance.
425  *
426  * Restore the SMPT registers to values previously stored in the
427  * SW data structures. Some MIC steppings lose register state
428  * across resets and this API should be called for performing
429  * a restore operation if required.
430  *
431  * returns None.
432  */
mic_smpt_restore(struct mic_device * mdev)433 void mic_smpt_restore(struct mic_device *mdev)
434 {
435 	int i;
436 	dma_addr_t dma_addr;
437 
438 	for (i = 0; i < mdev->smpt->info.num_reg; i++) {
439 		dma_addr = mdev->smpt->entry[i].dma_addr;
440 		mdev->smpt_ops->set(mdev, dma_addr, i);
441 	}
442 }
443