Updated `README.md` with instructions for building/using the kernel module.
[xeon-phi-kernel-module] / host / micpsmi.c
CommitLineData
800f879a
AT
1/*
2 * Copyright 2010-2017 Intel Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License, version 2,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
12 *
13 * Disclaimer: The codes contained in these modules may be specific to
14 * the Intel Software Development Platform codenamed Knights Ferry,
15 * and the Intel product codenamed Knights Corner, and are not backward
16 * compatible with other Intel products. Additionally, Intel will NOT
17 * support the codes or instruction set in future products.
18 *
19 * Intel offers no warranty of any kind regarding the code. This code is
20 * licensed on an "AS IS" basis and Intel is not obligated to provide
21 * any support, assistance, installation, training, or other services
22 * of any kind. Intel is also not obligated to provide any updates,
23 * enhancements or extensions. Intel specifically disclaims any warranty
24 * of merchantability, non-infringement, fitness for any particular
25 * purpose, and any other warranty.
26 *
27 * Further, Intel disclaims all liability of any kind, including but
28 * not limited to liability for infringement of any proprietary rights,
29 * relating to the use of the code, even if Intel is notified of the
30 * possibility of such liability. Except as expressly stated in an Intel
31 * license agreement provided with this code and agreed upon with Intel,
32 * no license, express or implied, by estoppel or otherwise, to any
33 * intellectual property rights is granted herein.
34 */
35
36#include "micint.h"
37
38bool mic_psmi_enable = 0;
39
40extern struct bin_attribute mic_psmi_ptes_attr;
41
42static __always_inline void
43mic_psmi_free_pte(mic_ctx_t *mic_ctx, int i)
44{
45 pci_unmap_single(mic_ctx->bi_pdev,
46 mic_ctx->bi_psmi.dma_tbl[i].pa, MIC_PSMI_PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
47 free_pages(mic_ctx->bi_psmi.va_tbl[i - 1].pa, MIC_PSMI_PAGE_ORDER);
48}
49
50static int mic_psmi_alloc_buffer(mic_ctx_t *mic_ctx)
51{
52 int i, j, ret;
53 void *va;
54 dma_addr_t dma_hndl;
55 struct mic_psmi_ctx *psmi_ctx = &mic_ctx->bi_psmi;
56
57 /* allocate psmi page tables */
58 psmi_ctx->nr_dma_pages =
59 ALIGN(psmi_ctx->dma_mem_size,
60 MIC_PSMI_PAGE_SIZE) / MIC_PSMI_PAGE_SIZE;
61 if ((psmi_ctx->va_tbl =
62 kmalloc(psmi_ctx->nr_dma_pages *
63 sizeof(struct mic_psmi_pte), GFP_KERNEL)) == NULL) {
64 printk("mic: psmi va table alloc failed\n");
65 return -ENOMEM;
66 }
67 psmi_ctx->dma_tbl_size =
68 (psmi_ctx->nr_dma_pages + 2) * sizeof(struct mic_psmi_pte);
69 if ((psmi_ctx->dma_tbl =
70 kmalloc(psmi_ctx->dma_tbl_size, GFP_KERNEL)) == NULL) {
71 printk("mic: psmi dma table alloc failed\n");
72 ret = -ENOMEM;
73 goto free_va_tbl;
74 }
75 psmi_ctx->dma_tbl_hndl =
76 pci_map_single(mic_ctx->bi_pdev,
77 psmi_ctx->dma_tbl, psmi_ctx->dma_tbl_size, PCI_DMA_BIDIRECTIONAL);
78 if (pci_dma_mapping_error(mic_ctx->bi_pdev,
79 psmi_ctx->dma_tbl_hndl)) {
80 printk("mic: psmi dma table mapping failed\n");
81 ret = -ENOMEM;
82 goto free_dma_tbl;
83 }
84
85 /* allocate psmi pages */
86 for (i = 0; i < psmi_ctx->nr_dma_pages; i++) {
87 if ((va = (void *)__get_free_pages(
88 GFP_KERNEL | __GFP_HIGHMEM,
89 MIC_PSMI_PAGE_ORDER)) == NULL) {
90 printk("mic: psmi page alloc failed: %d\n", i);
91 ret = -ENOMEM;
92 goto free_ptes;
93 }
94 memset(va, 0, MIC_PSMI_PAGE_SIZE);
95 dma_hndl = pci_map_single(mic_ctx->bi_pdev, va,
96 MIC_PSMI_PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
97 if (pci_dma_mapping_error(mic_ctx->bi_pdev, dma_hndl)) {
98 printk("mic: psmi page mapping failed: %d\n", i);
99 free_pages((unsigned long)va, MIC_PSMI_PAGE_ORDER);
100 ret = -ENOMEM;
101 goto free_ptes;
102 }
103 psmi_ctx->dma_tbl[i + 1].pa = dma_hndl;
104 psmi_ctx->va_tbl[i].pa = (uint64_t)va;
105 }
106 psmi_ctx->dma_tbl[0].pa = MIC_PSMI_SIGNATURE;
107 psmi_ctx->dma_tbl[psmi_ctx->nr_dma_pages + 1].pa = MIC_PSMI_SIGNATURE;
108 printk("mic: psmi #%d, %ld bytes, "
109 "dma_tbl va=0x%lx hndl=0x%lx\n", mic_ctx->bi_id + 1,
110 (unsigned long)psmi_ctx->dma_mem_size,
111 (unsigned long)psmi_ctx->dma_tbl,
112 (unsigned long)psmi_ctx->dma_tbl_hndl);
113 return 0;
114free_ptes:
115 for (j = 1; j < i; j++)
116 mic_psmi_free_pte(mic_ctx, j);
117 pci_unmap_single(mic_ctx->bi_pdev,
118 psmi_ctx->dma_tbl_hndl, psmi_ctx->dma_tbl_size, PCI_DMA_BIDIRECTIONAL);
119free_dma_tbl:
120 kfree(psmi_ctx->dma_tbl);
121 psmi_ctx->dma_tbl = NULL;
122free_va_tbl:
123 kfree(psmi_ctx->va_tbl);
124 psmi_ctx->va_tbl = NULL;
125 return ret;
126}
127
128static void mic_psmi_free_buffer(mic_ctx_t *mic_ctx)
129{
130 struct mic_psmi_ctx *psmi_ctx = &mic_ctx->bi_psmi;
131 int i;
132
133 for (i = 1; i <= psmi_ctx->nr_dma_pages; i++)
134 mic_psmi_free_pte(mic_ctx, i);
135 pci_unmap_single(mic_ctx->bi_pdev,
136 psmi_ctx->dma_tbl_hndl, psmi_ctx->dma_tbl_size, PCI_DMA_BIDIRECTIONAL);
137 kfree(psmi_ctx->dma_tbl);
138 psmi_ctx->dma_tbl = NULL;
139 kfree(psmi_ctx->va_tbl);
140 psmi_ctx->va_tbl = NULL;
141 printk("mic: psmi freed %ld bytes for board #%d\n",
142 (unsigned long)psmi_ctx->dma_mem_size, mic_ctx->bi_id + 1);
143}
144
145extern int usagemode_param;
146
147int mic_psmi_init(mic_ctx_t *mic_ctx)
148{
149 int ret;
150 int status = 0;
151 uint32_t scratch0;
152 struct mic_psmi_ctx * psmi_ctx = &mic_ctx->bi_psmi;
153
154 psmi_ctx->enabled = 0;
155 /* Only initialize psmi for the first board */
156 if (!mic_psmi_enable || mic_ctx->bi_id)
157 return 0;
158 if(!(scratch0 = SBOX_READ(mic_ctx->mmio.va, SBOX_SCRATCH0))) {
159 status = wait_for_bootstrap(mic_ctx->mmio.va);
160 scratch0 = SBOX_READ(mic_ctx->mmio.va, SBOX_SCRATCH0);
161 }
162 /* Memory size includes 512K reserved for VGA & GTT table */
163 psmi_ctx->dma_mem_size =
164 SCRATCH0_MEM_SIZE_KB(scratch0) * ((1) * 1024) +
165 MIC_PSMI_PAGE_SIZE;
166 if (USAGE_MODE_NORMAL == usagemode_param) {
167 if ((ret = mic_psmi_alloc_buffer(mic_ctx)))
168 return ret;
169 mic_psmi_ptes_attr.size = psmi_ctx->dma_tbl_size;
170 }
171 psmi_ctx->enabled = 1;
172 return 0;
173}
174
175void mic_psmi_uninit(mic_ctx_t *mic_ctx)
176{
177 struct mic_psmi_ctx * psmi_ctx = &mic_ctx->bi_psmi;
178
179 if (!psmi_ctx->enabled)
180 return;
181 if (USAGE_MODE_NORMAL == usagemode_param)
182 mic_psmi_free_buffer(mic_ctx);
183 psmi_ctx->enabled = 0;
184}