blob: 64180f46c8959abbd79988d0545a3eebdbe1418f [file] [log] [blame]
Dan Williams4cdadfd2021-02-16 20:09:50 -08001// SPDX-License-Identifier: GPL-2.0-only
2/* Copyright(c) 2020 Intel Corporation. All rights reserved. */
Dan Williams4faf31b2021-09-08 22:12:32 -07003#include <linux/io-64-nonatomic-lo-hi.h>
Dan Williams4cdadfd2021-02-16 20:09:50 -08004#include <linux/module.h>
Dan Williamsfae88172021-04-16 17:43:30 -07005#include <linux/sizes.h>
Dan Williamsb39cb102021-02-16 20:09:52 -08006#include <linux/mutex.h>
Ira Weiny30af9722021-06-03 17:50:36 -07007#include <linux/list.h>
Dan Williams4cdadfd2021-02-16 20:09:50 -08008#include <linux/pci.h>
9#include <linux/io.h>
Ben Widawsky5161a552021-08-02 10:29:38 -070010#include "cxlmem.h"
Dan Williams4cdadfd2021-02-16 20:09:50 -080011#include "pci.h"
Ben Widawsky8adaf742021-02-16 20:09:51 -080012#include "cxl.h"
13
14/**
Ben Widawsky21e9f762021-05-26 10:44:13 -070015 * DOC: cxl pci
Ben Widawsky8adaf742021-02-16 20:09:51 -080016 *
Ben Widawsky21e9f762021-05-26 10:44:13 -070017 * This implements the PCI exclusive functionality for a CXL device as it is
18 * defined by the Compute Express Link specification. CXL devices may surface
Ben Widawskyed97afb2021-09-13 09:33:24 -070019 * certain functionality even if it isn't CXL enabled. While this driver is
20 * focused around the PCI specific aspects of a CXL device, it binds to the
21 * specific CXL memory device class code, and therefore the implementation of
22 * cxl_pci is focused around CXL memory devices.
Ben Widawsky8adaf742021-02-16 20:09:51 -080023 *
24 * The driver has several responsibilities, mainly:
25 * - Create the memX device and register on the CXL bus.
26 * - Enumerate device's register interface and map them.
Ben Widawskyed97afb2021-09-13 09:33:24 -070027 * - Registers nvdimm bridge device with cxl_core.
28 * - Registers a CXL mailbox with cxl_core.
Ben Widawsky8adaf742021-02-16 20:09:51 -080029 */
30
31#define cxl_doorbell_busy(cxlm) \
Dan Williams8ac75dd2021-05-13 22:21:54 -070032 (readl((cxlm)->regs.mbox + CXLDEV_MBOX_CTRL_OFFSET) & \
Ben Widawsky8adaf742021-02-16 20:09:51 -080033 CXLDEV_MBOX_CTRL_DOORBELL)
34
35/* CXL 2.0 - 8.2.8.4 */
36#define CXL_MAILBOX_TIMEOUT_MS (2 * HZ)
37
Ben Widawskyed97afb2021-09-13 09:33:24 -070038static int cxl_pci_mbox_wait_for_doorbell(struct cxl_mem *cxlm)
Ben Widawsky8adaf742021-02-16 20:09:51 -080039{
40 const unsigned long start = jiffies;
41 unsigned long end = start;
42
43 while (cxl_doorbell_busy(cxlm)) {
44 end = jiffies;
45
46 if (time_after(end, start + CXL_MAILBOX_TIMEOUT_MS)) {
47 /* Check again in case preempted before timeout test */
48 if (!cxl_doorbell_busy(cxlm))
49 break;
50 return -ETIMEDOUT;
51 }
52 cpu_relax();
53 }
54
Dan Williams99e222a2021-09-08 22:12:09 -070055 dev_dbg(cxlm->dev, "Doorbell wait took %dms",
Ben Widawsky8adaf742021-02-16 20:09:51 -080056 jiffies_to_msecs(end) - jiffies_to_msecs(start));
57 return 0;
58}
59
Ben Widawskyed97afb2021-09-13 09:33:24 -070060static void cxl_pci_mbox_timeout(struct cxl_mem *cxlm,
Dan Williamsb64955a2021-09-08 22:12:21 -070061 struct cxl_mbox_cmd *mbox_cmd)
Ben Widawsky8adaf742021-02-16 20:09:51 -080062{
Dan Williams99e222a2021-09-08 22:12:09 -070063 struct device *dev = cxlm->dev;
Ben Widawsky8adaf742021-02-16 20:09:51 -080064
65 dev_dbg(dev, "Mailbox command (opcode: %#x size: %zub) timed out\n",
66 mbox_cmd->opcode, mbox_cmd->size_in);
67}
68
69/**
Ben Widawskyed97afb2021-09-13 09:33:24 -070070 * __cxl_pci_mbox_send_cmd() - Execute a mailbox command
Ben Widawsky8adaf742021-02-16 20:09:51 -080071 * @cxlm: The CXL memory device to communicate with.
72 * @mbox_cmd: Command to send to the memory device.
73 *
74 * Context: Any context. Expects mbox_mutex to be held.
75 * Return: -ETIMEDOUT if timeout occurred waiting for completion. 0 on success.
76 * Caller should check the return code in @mbox_cmd to make sure it
77 * succeeded.
78 *
79 * This is a generic form of the CXL mailbox send command thus only using the
80 * registers defined by the mailbox capability ID - CXL 2.0 8.2.8.4. Memory
81 * devices, and perhaps other types of CXL devices may have further information
82 * available upon error conditions. Driver facilities wishing to send mailbox
83 * commands should use the wrapper command.
84 *
85 * The CXL spec allows for up to two mailboxes. The intention is for the primary
86 * mailbox to be OS controlled and the secondary mailbox to be used by system
87 * firmware. This allows the OS and firmware to communicate with the device and
88 * not need to coordinate with each other. The driver only uses the primary
89 * mailbox.
90 */
Ben Widawskyed97afb2021-09-13 09:33:24 -070091static int __cxl_pci_mbox_send_cmd(struct cxl_mem *cxlm,
Dan Williamsb64955a2021-09-08 22:12:21 -070092 struct cxl_mbox_cmd *mbox_cmd)
Ben Widawsky8adaf742021-02-16 20:09:51 -080093{
Dan Williams8ac75dd2021-05-13 22:21:54 -070094 void __iomem *payload = cxlm->regs.mbox + CXLDEV_MBOX_PAYLOAD_OFFSET;
Dan Williams99e222a2021-09-08 22:12:09 -070095 struct device *dev = cxlm->dev;
Ben Widawsky8adaf742021-02-16 20:09:51 -080096 u64 cmd_reg, status_reg;
97 size_t out_len;
98 int rc;
99
100 lockdep_assert_held(&cxlm->mbox_mutex);
101
102 /*
103 * Here are the steps from 8.2.8.4 of the CXL 2.0 spec.
104 * 1. Caller reads MB Control Register to verify doorbell is clear
105 * 2. Caller writes Command Register
106 * 3. Caller writes Command Payload Registers if input payload is non-empty
107 * 4. Caller writes MB Control Register to set doorbell
108 * 5. Caller either polls for doorbell to be clear or waits for interrupt if configured
109 * 6. Caller reads MB Status Register to fetch Return code
110 * 7. If command successful, Caller reads Command Register to get Payload Length
111 * 8. If output payload is non-empty, host reads Command Payload Registers
112 *
113 * Hardware is free to do whatever it wants before the doorbell is rung,
114 * and isn't allowed to change anything after it clears the doorbell. As
115 * such, steps 2 and 3 can happen in any order, and steps 6, 7, 8 can
116 * also happen in any order (though some orders might not make sense).
117 */
118
119 /* #1 */
120 if (cxl_doorbell_busy(cxlm)) {
Dan Williams99e222a2021-09-08 22:12:09 -0700121 dev_err_ratelimited(dev, "Mailbox re-busy after acquiring\n");
Ben Widawsky8adaf742021-02-16 20:09:51 -0800122 return -EBUSY;
123 }
124
125 cmd_reg = FIELD_PREP(CXLDEV_MBOX_CMD_COMMAND_OPCODE_MASK,
126 mbox_cmd->opcode);
127 if (mbox_cmd->size_in) {
128 if (WARN_ON(!mbox_cmd->payload_in))
129 return -EINVAL;
130
131 cmd_reg |= FIELD_PREP(CXLDEV_MBOX_CMD_PAYLOAD_LENGTH_MASK,
132 mbox_cmd->size_in);
133 memcpy_toio(payload, mbox_cmd->payload_in, mbox_cmd->size_in);
134 }
135
136 /* #2, #3 */
Dan Williams8ac75dd2021-05-13 22:21:54 -0700137 writeq(cmd_reg, cxlm->regs.mbox + CXLDEV_MBOX_CMD_OFFSET);
Ben Widawsky8adaf742021-02-16 20:09:51 -0800138
139 /* #4 */
Dan Williams99e222a2021-09-08 22:12:09 -0700140 dev_dbg(dev, "Sending command\n");
Ben Widawsky8adaf742021-02-16 20:09:51 -0800141 writel(CXLDEV_MBOX_CTRL_DOORBELL,
Dan Williams8ac75dd2021-05-13 22:21:54 -0700142 cxlm->regs.mbox + CXLDEV_MBOX_CTRL_OFFSET);
Ben Widawsky8adaf742021-02-16 20:09:51 -0800143
144 /* #5 */
Ben Widawskyed97afb2021-09-13 09:33:24 -0700145 rc = cxl_pci_mbox_wait_for_doorbell(cxlm);
Ben Widawsky8adaf742021-02-16 20:09:51 -0800146 if (rc == -ETIMEDOUT) {
Ben Widawskyed97afb2021-09-13 09:33:24 -0700147 cxl_pci_mbox_timeout(cxlm, mbox_cmd);
Ben Widawsky8adaf742021-02-16 20:09:51 -0800148 return rc;
149 }
150
151 /* #6 */
Dan Williams8ac75dd2021-05-13 22:21:54 -0700152 status_reg = readq(cxlm->regs.mbox + CXLDEV_MBOX_STATUS_OFFSET);
Ben Widawsky8adaf742021-02-16 20:09:51 -0800153 mbox_cmd->return_code =
154 FIELD_GET(CXLDEV_MBOX_STATUS_RET_CODE_MASK, status_reg);
155
156 if (mbox_cmd->return_code != 0) {
Dan Williams99e222a2021-09-08 22:12:09 -0700157 dev_dbg(dev, "Mailbox operation had an error\n");
Ben Widawsky8adaf742021-02-16 20:09:51 -0800158 return 0;
159 }
160
161 /* #7 */
Dan Williams8ac75dd2021-05-13 22:21:54 -0700162 cmd_reg = readq(cxlm->regs.mbox + CXLDEV_MBOX_CMD_OFFSET);
Ben Widawsky8adaf742021-02-16 20:09:51 -0800163 out_len = FIELD_GET(CXLDEV_MBOX_CMD_PAYLOAD_LENGTH_MASK, cmd_reg);
164
165 /* #8 */
166 if (out_len && mbox_cmd->payload_out) {
167 /*
168 * Sanitize the copy. If hardware misbehaves, out_len per the
169 * spec can actually be greater than the max allowed size (21
170 * bits available but spec defined 1M max). The caller also may
171 * have requested less data than the hardware supplied even
172 * within spec.
173 */
174 size_t n = min3(mbox_cmd->size_out, cxlm->payload_size, out_len);
175
176 memcpy_fromio(mbox_cmd->payload_out, payload, n);
177 mbox_cmd->size_out = n;
178 } else {
179 mbox_cmd->size_out = 0;
180 }
181
182 return 0;
183}
184
185/**
Ben Widawskyed97afb2021-09-13 09:33:24 -0700186 * cxl_pci_mbox_get() - Acquire exclusive access to the mailbox.
Ben Widawsky8adaf742021-02-16 20:09:51 -0800187 * @cxlm: The memory device to gain access to.
188 *
189 * Context: Any context. Takes the mbox_mutex.
190 * Return: 0 if exclusive access was acquired.
191 */
Ben Widawskyed97afb2021-09-13 09:33:24 -0700192static int cxl_pci_mbox_get(struct cxl_mem *cxlm)
Ben Widawsky8adaf742021-02-16 20:09:51 -0800193{
Dan Williams99e222a2021-09-08 22:12:09 -0700194 struct device *dev = cxlm->dev;
Ben Widawsky8adaf742021-02-16 20:09:51 -0800195 u64 md_status;
196 int rc;
197
198 mutex_lock_io(&cxlm->mbox_mutex);
199
200 /*
201 * XXX: There is some amount of ambiguity in the 2.0 version of the spec
202 * around the mailbox interface ready (8.2.8.5.1.1). The purpose of the
203 * bit is to allow firmware running on the device to notify the driver
204 * that it's ready to receive commands. It is unclear if the bit needs
205 * to be read for each transaction mailbox, ie. the firmware can switch
206 * it on and off as needed. Second, there is no defined timeout for
207 * mailbox ready, like there is for the doorbell interface.
208 *
209 * Assumptions:
210 * 1. The firmware might toggle the Mailbox Interface Ready bit, check
211 * it for every command.
212 *
213 * 2. If the doorbell is clear, the firmware should have first set the
214 * Mailbox Interface Ready bit. Therefore, waiting for the doorbell
215 * to be ready is sufficient.
216 */
Ben Widawskyed97afb2021-09-13 09:33:24 -0700217 rc = cxl_pci_mbox_wait_for_doorbell(cxlm);
Ben Widawsky8adaf742021-02-16 20:09:51 -0800218 if (rc) {
219 dev_warn(dev, "Mailbox interface not ready\n");
220 goto out;
221 }
222
Dan Williams8ac75dd2021-05-13 22:21:54 -0700223 md_status = readq(cxlm->regs.memdev + CXLMDEV_STATUS_OFFSET);
Ben Widawsky8adaf742021-02-16 20:09:51 -0800224 if (!(md_status & CXLMDEV_MBOX_IF_READY && CXLMDEV_READY(md_status))) {
225 dev_err(dev, "mbox: reported doorbell ready, but not mbox ready\n");
226 rc = -EBUSY;
227 goto out;
228 }
229
230 /*
231 * Hardware shouldn't allow a ready status but also have failure bits
232 * set. Spit out an error, this should be a bug report
233 */
234 rc = -EFAULT;
235 if (md_status & CXLMDEV_DEV_FATAL) {
236 dev_err(dev, "mbox: reported ready, but fatal\n");
237 goto out;
238 }
239 if (md_status & CXLMDEV_FW_HALT) {
240 dev_err(dev, "mbox: reported ready, but halted\n");
241 goto out;
242 }
243 if (CXLMDEV_RESET_NEEDED(md_status)) {
244 dev_err(dev, "mbox: reported ready, but reset needed\n");
245 goto out;
246 }
247
248 /* with lock held */
249 return 0;
250
251out:
252 mutex_unlock(&cxlm->mbox_mutex);
253 return rc;
254}
255
256/**
Ben Widawskyed97afb2021-09-13 09:33:24 -0700257 * cxl_pci_mbox_put() - Release exclusive access to the mailbox.
Ben Widawsky8adaf742021-02-16 20:09:51 -0800258 * @cxlm: The CXL memory device to communicate with.
259 *
260 * Context: Any context. Expects mbox_mutex to be held.
261 */
Ben Widawskyed97afb2021-09-13 09:33:24 -0700262static void cxl_pci_mbox_put(struct cxl_mem *cxlm)
Ben Widawsky8adaf742021-02-16 20:09:51 -0800263{
264 mutex_unlock(&cxlm->mbox_mutex);
265}
266
Dan Williamsb64955a2021-09-08 22:12:21 -0700267static int cxl_pci_mbox_send(struct cxl_mem *cxlm, struct cxl_mbox_cmd *cmd)
268{
269 int rc;
270
Ben Widawskyed97afb2021-09-13 09:33:24 -0700271 rc = cxl_pci_mbox_get(cxlm);
Dan Williamsb64955a2021-09-08 22:12:21 -0700272 if (rc)
273 return rc;
274
Ben Widawskyed97afb2021-09-13 09:33:24 -0700275 rc = __cxl_pci_mbox_send_cmd(cxlm, cmd);
276 cxl_pci_mbox_put(cxlm);
Dan Williamsb64955a2021-09-08 22:12:21 -0700277
278 return rc;
279}
280
Ben Widawskyed97afb2021-09-13 09:33:24 -0700281static int cxl_pci_setup_mailbox(struct cxl_mem *cxlm)
Ben Widawsky8adaf742021-02-16 20:09:51 -0800282{
Dan Williams8ac75dd2021-05-13 22:21:54 -0700283 const int cap = readl(cxlm->regs.mbox + CXLDEV_MBOX_CAPS_OFFSET);
Ben Widawsky8adaf742021-02-16 20:09:51 -0800284
Dan Williamsb64955a2021-09-08 22:12:21 -0700285 cxlm->mbox_send = cxl_pci_mbox_send;
Ben Widawsky8adaf742021-02-16 20:09:51 -0800286 cxlm->payload_size =
287 1 << FIELD_GET(CXLDEV_MBOX_CAP_PAYLOAD_SIZE_MASK, cap);
288
289 /*
290 * CXL 2.0 8.2.8.4.3 Mailbox Capabilities Register
291 *
292 * If the size is too small, mandatory commands will not work and so
293 * there's no point in going forward. If the size is too large, there's
294 * no harm is soft limiting it.
295 */
296 cxlm->payload_size = min_t(size_t, cxlm->payload_size, SZ_1M);
297 if (cxlm->payload_size < 256) {
Dan Williams99e222a2021-09-08 22:12:09 -0700298 dev_err(cxlm->dev, "Mailbox is too small (%zub)",
Ben Widawsky8adaf742021-02-16 20:09:51 -0800299 cxlm->payload_size);
300 return -ENXIO;
301 }
302
Dan Williams99e222a2021-09-08 22:12:09 -0700303 dev_dbg(cxlm->dev, "Mailbox payload sized %zu",
Ben Widawsky8adaf742021-02-16 20:09:51 -0800304 cxlm->payload_size);
305
306 return 0;
307}
308
Ben Widawskyed97afb2021-09-13 09:33:24 -0700309static void __iomem *cxl_pci_map_regblock(struct cxl_mem *cxlm,
Ira Weiny07d62ea2021-05-27 17:49:18 -0700310 u8 bar, u64 offset)
Ben Widawsky1b0a1a22021-04-07 15:26:20 -0700311{
Ira Weinyf8a7e8c2021-05-27 17:49:19 -0700312 void __iomem *addr;
Dan Williams99e222a2021-09-08 22:12:09 -0700313 struct device *dev = cxlm->dev;
314 struct pci_dev *pdev = to_pci_dev(dev);
Ben Widawsky1b0a1a22021-04-07 15:26:20 -0700315
Ben Widawsky8adaf742021-02-16 20:09:51 -0800316 /* Basic sanity check that BAR is big enough */
317 if (pci_resource_len(pdev, bar) < offset) {
318 dev_err(dev, "BAR%d: %pr: too small (offset: %#llx)\n", bar,
319 &pdev->resource[bar], (unsigned long long)offset);
Ben Widawsky6630d312021-05-20 14:29:53 -0700320 return IOMEM_ERR_PTR(-ENXIO);
Ben Widawsky8adaf742021-02-16 20:09:51 -0800321 }
322
Ira Weiny30af9722021-06-03 17:50:36 -0700323 addr = pci_iomap(pdev, bar, 0);
Ira Weinyf8a7e8c2021-05-27 17:49:19 -0700324 if (!addr) {
Ben Widawsky8adaf742021-02-16 20:09:51 -0800325 dev_err(dev, "failed to map registers\n");
Ira Weinyf8a7e8c2021-05-27 17:49:19 -0700326 return addr;
Ben Widawsky8adaf742021-02-16 20:09:51 -0800327 }
Ben Widawsky8adaf742021-02-16 20:09:51 -0800328
Ira Weinyf8a7e8c2021-05-27 17:49:19 -0700329 dev_dbg(dev, "Mapped CXL Memory Device resource bar %u @ %#llx\n",
330 bar, offset);
Ben Widawsky6630d312021-05-20 14:29:53 -0700331
Ira Weiny30af9722021-06-03 17:50:36 -0700332 return addr;
333}
334
Ben Widawskyed97afb2021-09-13 09:33:24 -0700335static void cxl_pci_unmap_regblock(struct cxl_mem *cxlm, void __iomem *base)
Ira Weiny30af9722021-06-03 17:50:36 -0700336{
Dan Williams99e222a2021-09-08 22:12:09 -0700337 pci_iounmap(to_pci_dev(cxlm->dev), base);
Ben Widawsky8adaf742021-02-16 20:09:51 -0800338}
Dan Williams4cdadfd2021-02-16 20:09:50 -0800339
Ben Widawskyed97afb2021-09-13 09:33:24 -0700340static int cxl_pci_dvsec(struct pci_dev *pdev, int dvsec)
Dan Williams4cdadfd2021-02-16 20:09:50 -0800341{
342 int pos;
343
344 pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_DVSEC);
345 if (!pos)
346 return 0;
347
348 while (pos) {
349 u16 vendor, id;
350
351 pci_read_config_word(pdev, pos + PCI_DVSEC_HEADER1, &vendor);
352 pci_read_config_word(pdev, pos + PCI_DVSEC_HEADER2, &id);
353 if (vendor == PCI_DVSEC_VENDOR_ID_CXL && dvsec == id)
354 return pos;
355
356 pos = pci_find_next_ext_capability(pdev, pos,
357 PCI_EXT_CAP_ID_DVSEC);
358 }
359
360 return 0;
361}
362
Ira Weiny30af9722021-06-03 17:50:36 -0700363static int cxl_probe_regs(struct cxl_mem *cxlm, void __iomem *base,
364 struct cxl_register_map *map)
365{
Ben Widawsky08422372021-05-27 17:49:22 -0700366 struct cxl_component_reg_map *comp_map;
Ira Weiny30af9722021-06-03 17:50:36 -0700367 struct cxl_device_reg_map *dev_map;
Dan Williams99e222a2021-09-08 22:12:09 -0700368 struct device *dev = cxlm->dev;
Ira Weiny30af9722021-06-03 17:50:36 -0700369
370 switch (map->reg_type) {
Ben Widawsky08422372021-05-27 17:49:22 -0700371 case CXL_REGLOC_RBI_COMPONENT:
372 comp_map = &map->component_map;
373 cxl_probe_component_regs(dev, base, comp_map);
374 if (!comp_map->hdm_decoder.valid) {
375 dev_err(dev, "HDM decoder registers not found\n");
376 return -ENXIO;
377 }
378
379 dev_dbg(dev, "Set up component registers\n");
380 break;
Ira Weiny30af9722021-06-03 17:50:36 -0700381 case CXL_REGLOC_RBI_MEMDEV:
382 dev_map = &map->device_map;
383 cxl_probe_device_regs(dev, base, dev_map);
384 if (!dev_map->status.valid || !dev_map->mbox.valid ||
385 !dev_map->memdev.valid) {
386 dev_err(dev, "registers not found: %s%s%s\n",
387 !dev_map->status.valid ? "status " : "",
Li Qiang (Johnny Li)da582aa2021-09-03 19:20:50 -0700388 !dev_map->mbox.valid ? "mbox " : "",
389 !dev_map->memdev.valid ? "memdev " : "");
Ira Weiny30af9722021-06-03 17:50:36 -0700390 return -ENXIO;
391 }
392
393 dev_dbg(dev, "Probing device registers...\n");
394 break;
395 default:
396 break;
397 }
398
399 return 0;
400}
401
402static int cxl_map_regs(struct cxl_mem *cxlm, struct cxl_register_map *map)
403{
Dan Williams99e222a2021-09-08 22:12:09 -0700404 struct device *dev = cxlm->dev;
405 struct pci_dev *pdev = to_pci_dev(dev);
Ira Weiny30af9722021-06-03 17:50:36 -0700406
407 switch (map->reg_type) {
Ben Widawsky08422372021-05-27 17:49:22 -0700408 case CXL_REGLOC_RBI_COMPONENT:
409 cxl_map_component_regs(pdev, &cxlm->regs.component, map);
410 dev_dbg(dev, "Mapping component registers...\n");
411 break;
Ira Weiny30af9722021-06-03 17:50:36 -0700412 case CXL_REGLOC_RBI_MEMDEV:
413 cxl_map_device_regs(pdev, &cxlm->regs.device_regs, map);
414 dev_dbg(dev, "Probing device registers...\n");
415 break;
416 default:
417 break;
418 }
419
420 return 0;
421}
422
Ira Weiny07d62ea2021-05-27 17:49:18 -0700423static void cxl_decode_register_block(u32 reg_lo, u32 reg_hi,
424 u8 *bar, u64 *offset, u8 *reg_type)
425{
426 *offset = ((u64)reg_hi << 32) | (reg_lo & CXL_REGLOC_ADDR_MASK);
427 *bar = FIELD_GET(CXL_REGLOC_BIR_MASK, reg_lo);
428 *reg_type = FIELD_GET(CXL_REGLOC_RBI_MASK, reg_lo);
429}
430
Ben Widawsky1d5a4152021-04-07 15:26:21 -0700431/**
Ben Widawskyed97afb2021-09-13 09:33:24 -0700432 * cxl_pci_setup_regs() - Setup necessary MMIO.
Ben Widawsky1d5a4152021-04-07 15:26:21 -0700433 * @cxlm: The CXL memory device to communicate with.
434 *
435 * Return: 0 if all necessary registers mapped.
436 *
437 * A memory device is required by spec to implement a certain set of MMIO
438 * regions. The purpose of this function is to enumerate and map those
439 * registers.
440 */
Ben Widawskyed97afb2021-09-13 09:33:24 -0700441static int cxl_pci_setup_regs(struct cxl_mem *cxlm)
Ben Widawsky1d5a4152021-04-07 15:26:21 -0700442{
Ben Widawsky6630d312021-05-20 14:29:53 -0700443 void __iomem *base;
Dan Williams99e222a2021-09-08 22:12:09 -0700444 u32 regloc_size, regblocks;
445 int regloc, i, n_maps, ret = 0;
446 struct device *dev = cxlm->dev;
447 struct pci_dev *pdev = to_pci_dev(dev);
Ben Widawsky5b687052021-07-16 16:15:47 -0700448 struct cxl_register_map *map, maps[CXL_REGLOC_RBI_TYPES];
Ben Widawsky1d5a4152021-04-07 15:26:21 -0700449
Ben Widawskyed97afb2021-09-13 09:33:24 -0700450 regloc = cxl_pci_dvsec(pdev, PCI_DVSEC_ID_CXL_REGLOC_DVSEC_ID);
Ben Widawsky1d5a4152021-04-07 15:26:21 -0700451 if (!regloc) {
452 dev_err(dev, "register location dvsec not found\n");
453 return -ENXIO;
454 }
455
Ira Weinyf8a7e8c2021-05-27 17:49:19 -0700456 if (pci_request_mem_regions(pdev, pci_name(pdev)))
457 return -ENODEV;
458
Ben Widawsky1d5a4152021-04-07 15:26:21 -0700459 /* Get the size of the Register Locator DVSEC */
460 pci_read_config_dword(pdev, regloc + PCI_DVSEC_HEADER1, &regloc_size);
461 regloc_size = FIELD_GET(PCI_DVSEC_HEADER1_LENGTH_MASK, regloc_size);
462
463 regloc += PCI_DVSEC_ID_CXL_REGLOC_BLOCK1_OFFSET;
464 regblocks = (regloc_size - PCI_DVSEC_ID_CXL_REGLOC_BLOCK1_OFFSET) / 8;
465
Ben Widawsky5b687052021-07-16 16:15:47 -0700466 for (i = 0, n_maps = 0; i < regblocks; i++, regloc += 8) {
Ben Widawsky1d5a4152021-04-07 15:26:21 -0700467 u32 reg_lo, reg_hi;
468 u8 reg_type;
Ira Weiny07d62ea2021-05-27 17:49:18 -0700469 u64 offset;
470 u8 bar;
Ben Widawsky1d5a4152021-04-07 15:26:21 -0700471
Ben Widawsky1d5a4152021-04-07 15:26:21 -0700472 pci_read_config_dword(pdev, regloc, &reg_lo);
473 pci_read_config_dword(pdev, regloc + 4, &reg_hi);
474
Ira Weiny07d62ea2021-05-27 17:49:18 -0700475 cxl_decode_register_block(reg_lo, reg_hi, &bar, &offset,
476 &reg_type);
477
478 dev_dbg(dev, "Found register block in bar %u @ 0x%llx of type %u\n",
479 bar, offset, reg_type);
Ben Widawsky1d5a4152021-04-07 15:26:21 -0700480
Ben Widawsky1e39db52021-07-16 16:15:46 -0700481 /* Ignore unknown register block types */
482 if (reg_type > CXL_REGLOC_RBI_MEMDEV)
483 continue;
484
Ben Widawskyed97afb2021-09-13 09:33:24 -0700485 base = cxl_pci_map_regblock(cxlm, bar, offset);
Ben Widawsky5b687052021-07-16 16:15:47 -0700486 if (!base)
487 return -ENOMEM;
Ira Weiny30af9722021-06-03 17:50:36 -0700488
Ben Widawsky5b687052021-07-16 16:15:47 -0700489 map = &maps[n_maps];
Ira Weiny30af9722021-06-03 17:50:36 -0700490 map->barno = bar;
491 map->block_offset = offset;
492 map->reg_type = reg_type;
493
494 ret = cxl_probe_regs(cxlm, base + offset, map);
495
496 /* Always unmap the regblock regardless of probe success */
Ben Widawskyed97afb2021-09-13 09:33:24 -0700497 cxl_pci_unmap_regblock(cxlm, base);
Ira Weiny30af9722021-06-03 17:50:36 -0700498
499 if (ret)
Ben Widawsky5b687052021-07-16 16:15:47 -0700500 return ret;
501
502 n_maps++;
Ben Widawsky1d5a4152021-04-07 15:26:21 -0700503 }
504
Ira Weiny9a016522021-06-03 17:53:16 -0700505 pci_release_mem_regions(pdev);
506
Ben Widawsky5b687052021-07-16 16:15:47 -0700507 for (i = 0; i < n_maps; i++) {
508 ret = cxl_map_regs(cxlm, &maps[i]);
Ira Weiny30af9722021-06-03 17:50:36 -0700509 if (ret)
Ben Widawsky5b687052021-07-16 16:15:47 -0700510 break;
Ben Widawsky1d5a4152021-04-07 15:26:21 -0700511 }
512
Ira Weiny30af9722021-06-03 17:50:36 -0700513 return ret;
Ben Widawsky1d5a4152021-04-07 15:26:21 -0700514}
515
Ben Widawskyed97afb2021-09-13 09:33:24 -0700516static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
Dan Williams4cdadfd2021-02-16 20:09:50 -0800517{
Dan Williams21083f52021-06-15 16:36:31 -0700518 struct cxl_memdev *cxlmd;
Ben Widawsky1b0a1a22021-04-07 15:26:20 -0700519 struct cxl_mem *cxlm;
Ben Widawsky1d5a4152021-04-07 15:26:21 -0700520 int rc;
Ben Widawsky8adaf742021-02-16 20:09:51 -0800521
Dan Williams5a2328f2021-09-08 22:12:38 -0700522 /*
523 * Double check the anonymous union trickery in struct cxl_regs
524 * FIXME switch to struct_group()
525 */
526 BUILD_BUG_ON(offsetof(struct cxl_regs, memdev) !=
527 offsetof(struct cxl_regs, device_regs.memdev));
528
Ben Widawsky8adaf742021-02-16 20:09:51 -0800529 rc = pcim_enable_device(pdev);
530 if (rc)
531 return rc;
Dan Williams4cdadfd2021-02-16 20:09:50 -0800532
Dan Williams99e222a2021-09-08 22:12:09 -0700533 cxlm = cxl_mem_create(&pdev->dev);
Ben Widawsky1b0a1a22021-04-07 15:26:20 -0700534 if (IS_ERR(cxlm))
535 return PTR_ERR(cxlm);
536
Ben Widawskyed97afb2021-09-13 09:33:24 -0700537 rc = cxl_pci_setup_regs(cxlm);
Ben Widawsky8adaf742021-02-16 20:09:51 -0800538 if (rc)
539 return rc;
540
Ben Widawskyed97afb2021-09-13 09:33:24 -0700541 rc = cxl_pci_setup_mailbox(cxlm);
Ben Widawsky8adaf742021-02-16 20:09:51 -0800542 if (rc)
543 return rc;
544
Ben Widawsky472b1ce2021-02-16 20:09:55 -0800545 rc = cxl_mem_enumerate_cmds(cxlm);
546 if (rc)
547 return rc;
548
Dan Williamsb39cb102021-02-16 20:09:52 -0800549 rc = cxl_mem_identify(cxlm);
550 if (rc)
551 return rc;
552
Ira Weinyf8475022021-08-10 11:57:59 -0700553 rc = cxl_mem_create_range_info(cxlm);
554 if (rc)
555 return rc;
556
Dan Williams4faf31b2021-09-08 22:12:32 -0700557 cxlmd = devm_cxl_add_memdev(cxlm);
Dan Williams21083f52021-06-15 16:36:31 -0700558 if (IS_ERR(cxlmd))
559 return PTR_ERR(cxlmd);
560
561 if (range_len(&cxlm->pmem_range) && IS_ENABLED(CONFIG_CXL_PMEM))
562 rc = devm_cxl_add_nvdimm(&pdev->dev, cxlmd);
563
564 return rc;
Dan Williams4cdadfd2021-02-16 20:09:50 -0800565}
566
567static const struct pci_device_id cxl_mem_pci_tbl[] = {
568 /* PCI class code for CXL.mem Type-3 Devices */
569 { PCI_DEVICE_CLASS((PCI_CLASS_MEMORY_CXL << 8 | CXL_MEMORY_PROGIF), ~0)},
570 { /* terminate list */ },
571};
572MODULE_DEVICE_TABLE(pci, cxl_mem_pci_tbl);
573
Ben Widawskyed97afb2021-09-13 09:33:24 -0700574static struct pci_driver cxl_pci_driver = {
Dan Williams4cdadfd2021-02-16 20:09:50 -0800575 .name = KBUILD_MODNAME,
576 .id_table = cxl_mem_pci_tbl,
Ben Widawskyed97afb2021-09-13 09:33:24 -0700577 .probe = cxl_pci_probe,
Dan Williams4cdadfd2021-02-16 20:09:50 -0800578 .driver = {
579 .probe_type = PROBE_PREFER_ASYNCHRONOUS,
580 },
581};
582
583MODULE_LICENSE("GPL v2");
Ben Widawskyed97afb2021-09-13 09:33:24 -0700584module_pci_driver(cxl_pci_driver);
Dan Williamsb39cb102021-02-16 20:09:52 -0800585MODULE_IMPORT_NS(CXL);