15ef3166eSFrederic Barrat // SPDX-License-Identifier: GPL-2.0+
25ef3166eSFrederic Barrat // Copyright 2017 IBM Corp.
35ef3166eSFrederic Barrat #include <linux/pci.h>
45ef3166eSFrederic Barrat #include <asm/pnv-ocxl.h>
55ef3166eSFrederic Barrat #include <misc/ocxl-config.h>
6b696d282SAlastair D'Silva #include "ocxl_internal.h"
75ef3166eSFrederic Barrat
85ef3166eSFrederic Barrat #define EXTRACT_BIT(val, bit) (!!(val & BIT(bit)))
95ef3166eSFrederic Barrat #define EXTRACT_BITS(val, s, e) ((val & GENMASK(e, s)) >> s)
105ef3166eSFrederic Barrat
115ef3166eSFrederic Barrat #define OCXL_DVSEC_AFU_IDX_MASK GENMASK(5, 0)
125ef3166eSFrederic Barrat #define OCXL_DVSEC_ACTAG_MASK GENMASK(11, 0)
135ef3166eSFrederic Barrat #define OCXL_DVSEC_PASID_MASK GENMASK(19, 0)
145ef3166eSFrederic Barrat #define OCXL_DVSEC_PASID_LOG_MASK GENMASK(4, 0)
155ef3166eSFrederic Barrat
165ef3166eSFrederic Barrat #define OCXL_DVSEC_TEMPL_VERSION 0x0
175ef3166eSFrederic Barrat #define OCXL_DVSEC_TEMPL_NAME 0x4
185ef3166eSFrederic Barrat #define OCXL_DVSEC_TEMPL_AFU_VERSION 0x1C
195ef3166eSFrederic Barrat #define OCXL_DVSEC_TEMPL_MMIO_GLOBAL 0x20
205ef3166eSFrederic Barrat #define OCXL_DVSEC_TEMPL_MMIO_GLOBAL_SZ 0x28
215ef3166eSFrederic Barrat #define OCXL_DVSEC_TEMPL_MMIO_PP 0x30
225ef3166eSFrederic Barrat #define OCXL_DVSEC_TEMPL_MMIO_PP_SZ 0x38
2373a2b047SAlastair D'Silva #define OCXL_DVSEC_TEMPL_ALL_MEM_SZ 0x3C
2473a2b047SAlastair D'Silva #define OCXL_DVSEC_TEMPL_LPC_MEM_START 0x40
2573a2b047SAlastair D'Silva #define OCXL_DVSEC_TEMPL_WWID 0x48
2673a2b047SAlastair D'Silva #define OCXL_DVSEC_TEMPL_LPC_MEM_SZ 0x58
275ef3166eSFrederic Barrat
285ef3166eSFrederic Barrat #define OCXL_MAX_AFU_PER_FUNCTION 64
2973a2b047SAlastair D'Silva #define OCXL_TEMPL_LEN_1_0 0x58
3073a2b047SAlastair D'Silva #define OCXL_TEMPL_LEN_1_1 0x60
315ef3166eSFrederic Barrat #define OCXL_TEMPL_NAME_LEN 24
325ef3166eSFrederic Barrat #define OCXL_CFG_TIMEOUT 3
335ef3166eSFrederic Barrat
find_dvsec(struct pci_dev * dev,int dvsec_id)345ef3166eSFrederic Barrat static int find_dvsec(struct pci_dev *dev, int dvsec_id)
355ef3166eSFrederic Barrat {
36c6d7e134SBen Widawsky return pci_find_dvsec_capability(dev, PCI_VENDOR_ID_IBM, dvsec_id);
375ef3166eSFrederic Barrat }
385ef3166eSFrederic Barrat
find_dvsec_afu_ctrl(struct pci_dev * dev,u8 afu_idx)395ef3166eSFrederic Barrat static int find_dvsec_afu_ctrl(struct pci_dev *dev, u8 afu_idx)
405ef3166eSFrederic Barrat {
415ef3166eSFrederic Barrat int vsec = 0;
425ef3166eSFrederic Barrat u16 vendor, id;
435ef3166eSFrederic Barrat u8 idx;
445ef3166eSFrederic Barrat
455ef3166eSFrederic Barrat while ((vsec = pci_find_next_ext_capability(dev, vsec,
465ef3166eSFrederic Barrat OCXL_EXT_CAP_ID_DVSEC))) {
475ef3166eSFrederic Barrat pci_read_config_word(dev, vsec + OCXL_DVSEC_VENDOR_OFFSET,
485ef3166eSFrederic Barrat &vendor);
495ef3166eSFrederic Barrat pci_read_config_word(dev, vsec + OCXL_DVSEC_ID_OFFSET, &id);
505ef3166eSFrederic Barrat
515ef3166eSFrederic Barrat if (vendor == PCI_VENDOR_ID_IBM &&
525ef3166eSFrederic Barrat id == OCXL_DVSEC_AFU_CTRL_ID) {
535ef3166eSFrederic Barrat pci_read_config_byte(dev,
545ef3166eSFrederic Barrat vsec + OCXL_DVSEC_AFU_CTRL_AFU_IDX,
555ef3166eSFrederic Barrat &idx);
565ef3166eSFrederic Barrat if (idx == afu_idx)
575ef3166eSFrederic Barrat return vsec;
585ef3166eSFrederic Barrat }
595ef3166eSFrederic Barrat }
605ef3166eSFrederic Barrat return 0;
615ef3166eSFrederic Barrat }
625ef3166eSFrederic Barrat
6387db7579SPhilippe Bergheaud /**
6487db7579SPhilippe Bergheaud * get_function_0() - Find a related PCI device (function 0)
65a7c392c7SLee Jones * @dev: PCI device to match
6687db7579SPhilippe Bergheaud *
6787db7579SPhilippe Bergheaud * Returns a pointer to the related device, or null if not found
6887db7579SPhilippe Bergheaud */
get_function_0(struct pci_dev * dev)6987db7579SPhilippe Bergheaud static struct pci_dev *get_function_0(struct pci_dev *dev)
7087db7579SPhilippe Bergheaud {
7187db7579SPhilippe Bergheaud unsigned int devfn = PCI_DEVFN(PCI_SLOT(dev->devfn), 0);
7287db7579SPhilippe Bergheaud
7387db7579SPhilippe Bergheaud return pci_get_domain_bus_and_slot(pci_domain_nr(dev->bus),
7487db7579SPhilippe Bergheaud dev->bus->number, devfn);
7587db7579SPhilippe Bergheaud }
7687db7579SPhilippe Bergheaud
read_pasid(struct pci_dev * dev,struct ocxl_fn_config * fn)7732941494SAlastair D'Silva static void read_pasid(struct pci_dev *dev, struct ocxl_fn_config *fn)
785ef3166eSFrederic Barrat {
795ef3166eSFrederic Barrat u16 val;
805ef3166eSFrederic Barrat int pos;
815ef3166eSFrederic Barrat
825ef3166eSFrederic Barrat pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_PASID);
835ef3166eSFrederic Barrat if (!pos) {
845ef3166eSFrederic Barrat /*
855ef3166eSFrederic Barrat * PASID capability is not mandatory, but there
865ef3166eSFrederic Barrat * shouldn't be any AFU
875ef3166eSFrederic Barrat */
885ef3166eSFrederic Barrat dev_dbg(&dev->dev, "Function doesn't require any PASID\n");
895ef3166eSFrederic Barrat fn->max_pasid_log = -1;
905ef3166eSFrederic Barrat goto out;
915ef3166eSFrederic Barrat }
925ef3166eSFrederic Barrat pci_read_config_word(dev, pos + PCI_PASID_CAP, &val);
935ef3166eSFrederic Barrat fn->max_pasid_log = EXTRACT_BITS(val, 8, 12);
945ef3166eSFrederic Barrat
955ef3166eSFrederic Barrat out:
965ef3166eSFrederic Barrat dev_dbg(&dev->dev, "PASID capability:\n");
975ef3166eSFrederic Barrat dev_dbg(&dev->dev, " Max PASID log = %d\n", fn->max_pasid_log);
985ef3166eSFrederic Barrat }
995ef3166eSFrederic Barrat
read_dvsec_tl(struct pci_dev * dev,struct ocxl_fn_config * fn)1005ef3166eSFrederic Barrat static int read_dvsec_tl(struct pci_dev *dev, struct ocxl_fn_config *fn)
1015ef3166eSFrederic Barrat {
1025ef3166eSFrederic Barrat int pos;
1035ef3166eSFrederic Barrat
1045ef3166eSFrederic Barrat pos = find_dvsec(dev, OCXL_DVSEC_TL_ID);
1055ef3166eSFrederic Barrat if (!pos && PCI_FUNC(dev->devfn) == 0) {
1065ef3166eSFrederic Barrat dev_err(&dev->dev, "Can't find TL DVSEC\n");
1075ef3166eSFrederic Barrat return -ENODEV;
1085ef3166eSFrederic Barrat }
1095ef3166eSFrederic Barrat if (pos && PCI_FUNC(dev->devfn) != 0) {
1105ef3166eSFrederic Barrat dev_err(&dev->dev, "TL DVSEC is only allowed on function 0\n");
1115ef3166eSFrederic Barrat return -ENODEV;
1125ef3166eSFrederic Barrat }
1135ef3166eSFrederic Barrat fn->dvsec_tl_pos = pos;
1145ef3166eSFrederic Barrat return 0;
1155ef3166eSFrederic Barrat }
1165ef3166eSFrederic Barrat
read_dvsec_function(struct pci_dev * dev,struct ocxl_fn_config * fn)1175ef3166eSFrederic Barrat static int read_dvsec_function(struct pci_dev *dev, struct ocxl_fn_config *fn)
1185ef3166eSFrederic Barrat {
1195ef3166eSFrederic Barrat int pos, afu_present;
1205ef3166eSFrederic Barrat u32 val;
1215ef3166eSFrederic Barrat
1225ef3166eSFrederic Barrat pos = find_dvsec(dev, OCXL_DVSEC_FUNC_ID);
1235ef3166eSFrederic Barrat if (!pos) {
1245ef3166eSFrederic Barrat dev_err(&dev->dev, "Can't find function DVSEC\n");
1255ef3166eSFrederic Barrat return -ENODEV;
1265ef3166eSFrederic Barrat }
1275ef3166eSFrederic Barrat fn->dvsec_function_pos = pos;
1285ef3166eSFrederic Barrat
1295ef3166eSFrederic Barrat pci_read_config_dword(dev, pos + OCXL_DVSEC_FUNC_OFF_INDEX, &val);
1305ef3166eSFrederic Barrat afu_present = EXTRACT_BIT(val, 31);
1315ef3166eSFrederic Barrat if (!afu_present) {
1325ef3166eSFrederic Barrat fn->max_afu_index = -1;
1335ef3166eSFrederic Barrat dev_dbg(&dev->dev, "Function doesn't define any AFU\n");
1345ef3166eSFrederic Barrat goto out;
1355ef3166eSFrederic Barrat }
1365ef3166eSFrederic Barrat fn->max_afu_index = EXTRACT_BITS(val, 24, 29);
1375ef3166eSFrederic Barrat
1385ef3166eSFrederic Barrat out:
1395ef3166eSFrederic Barrat dev_dbg(&dev->dev, "Function DVSEC:\n");
1405ef3166eSFrederic Barrat dev_dbg(&dev->dev, " Max AFU index = %d\n", fn->max_afu_index);
1415ef3166eSFrederic Barrat return 0;
1425ef3166eSFrederic Barrat }
1435ef3166eSFrederic Barrat
read_dvsec_afu_info(struct pci_dev * dev,struct ocxl_fn_config * fn)1445ef3166eSFrederic Barrat static int read_dvsec_afu_info(struct pci_dev *dev, struct ocxl_fn_config *fn)
1455ef3166eSFrederic Barrat {
1465ef3166eSFrederic Barrat int pos;
1475ef3166eSFrederic Barrat
1485ef3166eSFrederic Barrat if (fn->max_afu_index < 0) {
1495ef3166eSFrederic Barrat fn->dvsec_afu_info_pos = -1;
1505ef3166eSFrederic Barrat return 0;
1515ef3166eSFrederic Barrat }
1525ef3166eSFrederic Barrat
1535ef3166eSFrederic Barrat pos = find_dvsec(dev, OCXL_DVSEC_AFU_INFO_ID);
1545ef3166eSFrederic Barrat if (!pos) {
1555ef3166eSFrederic Barrat dev_err(&dev->dev, "Can't find AFU information DVSEC\n");
1565ef3166eSFrederic Barrat return -ENODEV;
1575ef3166eSFrederic Barrat }
1585ef3166eSFrederic Barrat fn->dvsec_afu_info_pos = pos;
1595ef3166eSFrederic Barrat return 0;
1605ef3166eSFrederic Barrat }
1615ef3166eSFrederic Barrat
read_dvsec_vendor(struct pci_dev * dev)1625ef3166eSFrederic Barrat static int read_dvsec_vendor(struct pci_dev *dev)
1635ef3166eSFrederic Barrat {
1645ef3166eSFrederic Barrat int pos;
16587db7579SPhilippe Bergheaud u32 cfg, tlx, dlx, reset_reload;
1665ef3166eSFrederic Barrat
1675ef3166eSFrederic Barrat /*
16887db7579SPhilippe Bergheaud * vendor specific DVSEC, for IBM images only. Some older
16987db7579SPhilippe Bergheaud * images may not have it
1705ef3166eSFrederic Barrat *
17187db7579SPhilippe Bergheaud * It's only used on function 0 to specify the version of some
17287db7579SPhilippe Bergheaud * logic blocks and to give access to special registers to
17387db7579SPhilippe Bergheaud * enable host-based flashing.
1745ef3166eSFrederic Barrat */
1755ef3166eSFrederic Barrat if (PCI_FUNC(dev->devfn) != 0)
1765ef3166eSFrederic Barrat return 0;
1775ef3166eSFrederic Barrat
1785ef3166eSFrederic Barrat pos = find_dvsec(dev, OCXL_DVSEC_VENDOR_ID);
1795ef3166eSFrederic Barrat if (!pos)
1805ef3166eSFrederic Barrat return 0;
1815ef3166eSFrederic Barrat
1825ef3166eSFrederic Barrat pci_read_config_dword(dev, pos + OCXL_DVSEC_VENDOR_CFG_VERS, &cfg);
1835ef3166eSFrederic Barrat pci_read_config_dword(dev, pos + OCXL_DVSEC_VENDOR_TLX_VERS, &tlx);
1845ef3166eSFrederic Barrat pci_read_config_dword(dev, pos + OCXL_DVSEC_VENDOR_DLX_VERS, &dlx);
18587db7579SPhilippe Bergheaud pci_read_config_dword(dev, pos + OCXL_DVSEC_VENDOR_RESET_RELOAD,
18687db7579SPhilippe Bergheaud &reset_reload);
1875ef3166eSFrederic Barrat
1885ef3166eSFrederic Barrat dev_dbg(&dev->dev, "Vendor specific DVSEC:\n");
1895ef3166eSFrederic Barrat dev_dbg(&dev->dev, " CFG version = 0x%x\n", cfg);
1905ef3166eSFrederic Barrat dev_dbg(&dev->dev, " TLX version = 0x%x\n", tlx);
1915ef3166eSFrederic Barrat dev_dbg(&dev->dev, " DLX version = 0x%x\n", dlx);
19287db7579SPhilippe Bergheaud dev_dbg(&dev->dev, " ResetReload = 0x%x\n", reset_reload);
19387db7579SPhilippe Bergheaud return 0;
19487db7579SPhilippe Bergheaud }
19587db7579SPhilippe Bergheaud
196*27158c72SYang Yingliang /**
197*27158c72SYang Yingliang * get_dvsec_vendor0() - Find a related PCI device (function 0)
198*27158c72SYang Yingliang * @dev: PCI device to match
199*27158c72SYang Yingliang * @dev0: The PCI device (function 0) found
200*27158c72SYang Yingliang * @out_pos: The position of PCI device (function 0)
201*27158c72SYang Yingliang *
202*27158c72SYang Yingliang * Returns 0 on success, negative on failure.
203*27158c72SYang Yingliang *
204*27158c72SYang Yingliang * NOTE: If it's successful, the reference of dev0 is increased,
205*27158c72SYang Yingliang * so after using it, the callers must call pci_dev_put() to give
206*27158c72SYang Yingliang * up the reference.
207*27158c72SYang Yingliang */
get_dvsec_vendor0(struct pci_dev * dev,struct pci_dev ** dev0,int * out_pos)20887db7579SPhilippe Bergheaud static int get_dvsec_vendor0(struct pci_dev *dev, struct pci_dev **dev0,
20987db7579SPhilippe Bergheaud int *out_pos)
21087db7579SPhilippe Bergheaud {
21187db7579SPhilippe Bergheaud int pos;
21287db7579SPhilippe Bergheaud
21387db7579SPhilippe Bergheaud if (PCI_FUNC(dev->devfn) != 0) {
21487db7579SPhilippe Bergheaud dev = get_function_0(dev);
21587db7579SPhilippe Bergheaud if (!dev)
21687db7579SPhilippe Bergheaud return -1;
217*27158c72SYang Yingliang } else {
218*27158c72SYang Yingliang dev = pci_dev_get(dev);
21987db7579SPhilippe Bergheaud }
22087db7579SPhilippe Bergheaud pos = find_dvsec(dev, OCXL_DVSEC_VENDOR_ID);
221*27158c72SYang Yingliang if (!pos) {
222*27158c72SYang Yingliang pci_dev_put(dev);
22387db7579SPhilippe Bergheaud return -1;
224*27158c72SYang Yingliang }
22587db7579SPhilippe Bergheaud *dev0 = dev;
22687db7579SPhilippe Bergheaud *out_pos = pos;
22787db7579SPhilippe Bergheaud return 0;
22887db7579SPhilippe Bergheaud }
22987db7579SPhilippe Bergheaud
ocxl_config_get_reset_reload(struct pci_dev * dev,int * val)23087db7579SPhilippe Bergheaud int ocxl_config_get_reset_reload(struct pci_dev *dev, int *val)
23187db7579SPhilippe Bergheaud {
23287db7579SPhilippe Bergheaud struct pci_dev *dev0;
23387db7579SPhilippe Bergheaud u32 reset_reload;
23487db7579SPhilippe Bergheaud int pos;
23587db7579SPhilippe Bergheaud
23687db7579SPhilippe Bergheaud if (get_dvsec_vendor0(dev, &dev0, &pos))
23787db7579SPhilippe Bergheaud return -1;
23887db7579SPhilippe Bergheaud
23987db7579SPhilippe Bergheaud pci_read_config_dword(dev0, pos + OCXL_DVSEC_VENDOR_RESET_RELOAD,
24087db7579SPhilippe Bergheaud &reset_reload);
241*27158c72SYang Yingliang pci_dev_put(dev0);
24287db7579SPhilippe Bergheaud *val = !!(reset_reload & BIT(0));
24387db7579SPhilippe Bergheaud return 0;
24487db7579SPhilippe Bergheaud }
24587db7579SPhilippe Bergheaud
ocxl_config_set_reset_reload(struct pci_dev * dev,int val)24687db7579SPhilippe Bergheaud int ocxl_config_set_reset_reload(struct pci_dev *dev, int val)
24787db7579SPhilippe Bergheaud {
24887db7579SPhilippe Bergheaud struct pci_dev *dev0;
24987db7579SPhilippe Bergheaud u32 reset_reload;
25087db7579SPhilippe Bergheaud int pos;
25187db7579SPhilippe Bergheaud
25287db7579SPhilippe Bergheaud if (get_dvsec_vendor0(dev, &dev0, &pos))
25387db7579SPhilippe Bergheaud return -1;
25487db7579SPhilippe Bergheaud
25587db7579SPhilippe Bergheaud pci_read_config_dword(dev0, pos + OCXL_DVSEC_VENDOR_RESET_RELOAD,
25687db7579SPhilippe Bergheaud &reset_reload);
25787db7579SPhilippe Bergheaud if (val)
25887db7579SPhilippe Bergheaud reset_reload |= BIT(0);
25987db7579SPhilippe Bergheaud else
26087db7579SPhilippe Bergheaud reset_reload &= ~BIT(0);
26187db7579SPhilippe Bergheaud pci_write_config_dword(dev0, pos + OCXL_DVSEC_VENDOR_RESET_RELOAD,
26287db7579SPhilippe Bergheaud reset_reload);
263*27158c72SYang Yingliang pci_dev_put(dev0);
2645ef3166eSFrederic Barrat return 0;
2655ef3166eSFrederic Barrat }
2665ef3166eSFrederic Barrat
validate_function(struct pci_dev * dev,struct ocxl_fn_config * fn)2675ef3166eSFrederic Barrat static int validate_function(struct pci_dev *dev, struct ocxl_fn_config *fn)
2685ef3166eSFrederic Barrat {
2695ef3166eSFrederic Barrat if (fn->max_pasid_log == -1 && fn->max_afu_index >= 0) {
2705ef3166eSFrederic Barrat dev_err(&dev->dev,
2715ef3166eSFrederic Barrat "AFUs are defined but no PASIDs are requested\n");
2725ef3166eSFrederic Barrat return -EINVAL;
2735ef3166eSFrederic Barrat }
2745ef3166eSFrederic Barrat
2755ef3166eSFrederic Barrat if (fn->max_afu_index > OCXL_MAX_AFU_PER_FUNCTION) {
2765ef3166eSFrederic Barrat dev_err(&dev->dev,
2775ef3166eSFrederic Barrat "Max AFU index out of architectural limit (%d vs %d)\n",
2785ef3166eSFrederic Barrat fn->max_afu_index, OCXL_MAX_AFU_PER_FUNCTION);
2795ef3166eSFrederic Barrat return -EINVAL;
2805ef3166eSFrederic Barrat }
2815ef3166eSFrederic Barrat return 0;
2825ef3166eSFrederic Barrat }
2835ef3166eSFrederic Barrat
ocxl_config_read_function(struct pci_dev * dev,struct ocxl_fn_config * fn)2845ef3166eSFrederic Barrat int ocxl_config_read_function(struct pci_dev *dev, struct ocxl_fn_config *fn)
2855ef3166eSFrederic Barrat {
2865ef3166eSFrederic Barrat int rc;
2875ef3166eSFrederic Barrat
28832941494SAlastair D'Silva read_pasid(dev, fn);
2895ef3166eSFrederic Barrat
2905ef3166eSFrederic Barrat rc = read_dvsec_tl(dev, fn);
2915ef3166eSFrederic Barrat if (rc) {
2925ef3166eSFrederic Barrat dev_err(&dev->dev,
2935ef3166eSFrederic Barrat "Invalid Transaction Layer DVSEC configuration: %d\n",
2945ef3166eSFrederic Barrat rc);
2955ef3166eSFrederic Barrat return -ENODEV;
2965ef3166eSFrederic Barrat }
2975ef3166eSFrederic Barrat
2985ef3166eSFrederic Barrat rc = read_dvsec_function(dev, fn);
2995ef3166eSFrederic Barrat if (rc) {
3005ef3166eSFrederic Barrat dev_err(&dev->dev,
3015ef3166eSFrederic Barrat "Invalid Function DVSEC configuration: %d\n", rc);
3025ef3166eSFrederic Barrat return -ENODEV;
3035ef3166eSFrederic Barrat }
3045ef3166eSFrederic Barrat
3055ef3166eSFrederic Barrat rc = read_dvsec_afu_info(dev, fn);
3065ef3166eSFrederic Barrat if (rc) {
3075ef3166eSFrederic Barrat dev_err(&dev->dev, "Invalid AFU configuration: %d\n", rc);
3085ef3166eSFrederic Barrat return -ENODEV;
3095ef3166eSFrederic Barrat }
3105ef3166eSFrederic Barrat
3115ef3166eSFrederic Barrat rc = read_dvsec_vendor(dev);
3125ef3166eSFrederic Barrat if (rc) {
3135ef3166eSFrederic Barrat dev_err(&dev->dev,
3145ef3166eSFrederic Barrat "Invalid vendor specific DVSEC configuration: %d\n",
3155ef3166eSFrederic Barrat rc);
3165ef3166eSFrederic Barrat return -ENODEV;
3175ef3166eSFrederic Barrat }
3185ef3166eSFrederic Barrat
3195ef3166eSFrederic Barrat rc = validate_function(dev, fn);
3205ef3166eSFrederic Barrat return rc;
3215ef3166eSFrederic Barrat }
322280b983cSFrederic Barrat EXPORT_SYMBOL_GPL(ocxl_config_read_function);
3235ef3166eSFrederic Barrat
read_afu_info(struct pci_dev * dev,struct ocxl_fn_config * fn,int offset,u32 * data)3245ef3166eSFrederic Barrat static int read_afu_info(struct pci_dev *dev, struct ocxl_fn_config *fn,
3255ef3166eSFrederic Barrat int offset, u32 *data)
3265ef3166eSFrederic Barrat {
3275ef3166eSFrederic Barrat u32 val;
3285ef3166eSFrederic Barrat unsigned long timeout = jiffies + (HZ * OCXL_CFG_TIMEOUT);
3295ef3166eSFrederic Barrat int pos = fn->dvsec_afu_info_pos;
3305ef3166eSFrederic Barrat
3315ef3166eSFrederic Barrat /* Protect 'data valid' bit */
3325ef3166eSFrederic Barrat if (EXTRACT_BIT(offset, 31)) {
3335ef3166eSFrederic Barrat dev_err(&dev->dev, "Invalid offset in AFU info DVSEC\n");
3345ef3166eSFrederic Barrat return -EINVAL;
3355ef3166eSFrederic Barrat }
3365ef3166eSFrederic Barrat
3375ef3166eSFrederic Barrat pci_write_config_dword(dev, pos + OCXL_DVSEC_AFU_INFO_OFF, offset);
3385ef3166eSFrederic Barrat pci_read_config_dword(dev, pos + OCXL_DVSEC_AFU_INFO_OFF, &val);
3395ef3166eSFrederic Barrat while (!EXTRACT_BIT(val, 31)) {
3405ef3166eSFrederic Barrat if (time_after_eq(jiffies, timeout)) {
3415ef3166eSFrederic Barrat dev_err(&dev->dev,
3425ef3166eSFrederic Barrat "Timeout while reading AFU info DVSEC (offset=%d)\n",
3435ef3166eSFrederic Barrat offset);
3445ef3166eSFrederic Barrat return -EBUSY;
3455ef3166eSFrederic Barrat }
3465ef3166eSFrederic Barrat cpu_relax();
3475ef3166eSFrederic Barrat pci_read_config_dword(dev, pos + OCXL_DVSEC_AFU_INFO_OFF, &val);
3485ef3166eSFrederic Barrat }
3495ef3166eSFrederic Barrat pci_read_config_dword(dev, pos + OCXL_DVSEC_AFU_INFO_DATA, data);
3505ef3166eSFrederic Barrat return 0;
3515ef3166eSFrederic Barrat }
3525ef3166eSFrederic Barrat
35373a2b047SAlastair D'Silva /**
3543591538aSAlastair D'Silva * read_template_version() - Read the template version from the AFU
3553591538aSAlastair D'Silva * @dev: the device for the AFU
3563591538aSAlastair D'Silva * @fn: the AFU offsets
3573591538aSAlastair D'Silva * @len: outputs the template length
3583591538aSAlastair D'Silva * @version: outputs the major<<8,minor version
35973a2b047SAlastair D'Silva *
36073a2b047SAlastair D'Silva * Returns 0 on success, negative on failure
36173a2b047SAlastair D'Silva */
read_template_version(struct pci_dev * dev,struct ocxl_fn_config * fn,u16 * len,u16 * version)36273a2b047SAlastair D'Silva static int read_template_version(struct pci_dev *dev, struct ocxl_fn_config *fn,
36373a2b047SAlastair D'Silva u16 *len, u16 *version)
36473a2b047SAlastair D'Silva {
36573a2b047SAlastair D'Silva u32 val32;
36673a2b047SAlastair D'Silva u8 major, minor;
36773a2b047SAlastair D'Silva int rc;
36873a2b047SAlastair D'Silva
36973a2b047SAlastair D'Silva rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_VERSION, &val32);
37073a2b047SAlastair D'Silva if (rc)
37173a2b047SAlastair D'Silva return rc;
37273a2b047SAlastair D'Silva
37373a2b047SAlastair D'Silva *len = EXTRACT_BITS(val32, 16, 31);
37473a2b047SAlastair D'Silva major = EXTRACT_BITS(val32, 8, 15);
37573a2b047SAlastair D'Silva minor = EXTRACT_BITS(val32, 0, 7);
37673a2b047SAlastair D'Silva *version = (major << 8) + minor;
37773a2b047SAlastair D'Silva return 0;
37873a2b047SAlastair D'Silva }
37973a2b047SAlastair D'Silva
ocxl_config_check_afu_index(struct pci_dev * dev,struct ocxl_fn_config * fn,int afu_idx)3805ef3166eSFrederic Barrat int ocxl_config_check_afu_index(struct pci_dev *dev,
3815ef3166eSFrederic Barrat struct ocxl_fn_config *fn, int afu_idx)
3825ef3166eSFrederic Barrat {
38373a2b047SAlastair D'Silva int rc;
38473a2b047SAlastair D'Silva u16 templ_version;
38573a2b047SAlastair D'Silva u16 len, expected_len;
3865ef3166eSFrederic Barrat
3876f8e45f7SChristophe Lombard pci_write_config_byte(dev,
3886f8e45f7SChristophe Lombard fn->dvsec_afu_info_pos + OCXL_DVSEC_AFU_INFO_AFU_IDX,
3896f8e45f7SChristophe Lombard afu_idx);
39073a2b047SAlastair D'Silva
39173a2b047SAlastair D'Silva rc = read_template_version(dev, fn, &len, &templ_version);
3925ef3166eSFrederic Barrat if (rc)
3935ef3166eSFrederic Barrat return rc;
3945ef3166eSFrederic Barrat
39573a2b047SAlastair D'Silva /* AFU index map can have holes, in which case we read all 0's */
39673a2b047SAlastair D'Silva if (!templ_version && !len)
3975ef3166eSFrederic Barrat return 0;
3985ef3166eSFrederic Barrat
3995ef3166eSFrederic Barrat dev_dbg(&dev->dev, "AFU descriptor template version %d.%d\n",
40073a2b047SAlastair D'Silva templ_version >> 8, templ_version & 0xFF);
4015ef3166eSFrederic Barrat
40273a2b047SAlastair D'Silva switch (templ_version) {
40373a2b047SAlastair D'Silva case 0x0005: // v0.5 was used prior to the spec approval
40473a2b047SAlastair D'Silva case 0x0100:
40573a2b047SAlastair D'Silva expected_len = OCXL_TEMPL_LEN_1_0;
40673a2b047SAlastair D'Silva break;
40773a2b047SAlastair D'Silva case 0x0101:
40873a2b047SAlastair D'Silva expected_len = OCXL_TEMPL_LEN_1_1;
40973a2b047SAlastair D'Silva break;
41073a2b047SAlastair D'Silva default:
41173a2b047SAlastair D'Silva dev_warn(&dev->dev, "Unknown AFU template version %#x\n",
41273a2b047SAlastair D'Silva templ_version);
41373a2b047SAlastair D'Silva expected_len = len;
4145ef3166eSFrederic Barrat }
41573a2b047SAlastair D'Silva if (len != expected_len)
41673a2b047SAlastair D'Silva dev_warn(&dev->dev,
41773a2b047SAlastair D'Silva "Unexpected template length %#x in AFU information, expected %#x for version %#x\n",
41873a2b047SAlastair D'Silva len, expected_len, templ_version);
4195ef3166eSFrederic Barrat return 1;
4205ef3166eSFrederic Barrat }
4215ef3166eSFrederic Barrat
read_afu_name(struct pci_dev * dev,struct ocxl_fn_config * fn,struct ocxl_afu_config * afu)4225ef3166eSFrederic Barrat static int read_afu_name(struct pci_dev *dev, struct ocxl_fn_config *fn,
4235ef3166eSFrederic Barrat struct ocxl_afu_config *afu)
4245ef3166eSFrederic Barrat {
4255ef3166eSFrederic Barrat int i, rc;
4265ef3166eSFrederic Barrat u32 val, *ptr;
4275ef3166eSFrederic Barrat
4285ef3166eSFrederic Barrat BUILD_BUG_ON(OCXL_AFU_NAME_SZ < OCXL_TEMPL_NAME_LEN);
4295ef3166eSFrederic Barrat for (i = 0; i < OCXL_TEMPL_NAME_LEN; i += 4) {
4305ef3166eSFrederic Barrat rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_NAME + i, &val);
4315ef3166eSFrederic Barrat if (rc)
4325ef3166eSFrederic Barrat return rc;
4335ef3166eSFrederic Barrat ptr = (u32 *) &afu->name[i];
4342f07229fSGreg Kurz *ptr = le32_to_cpu((__force __le32) val);
4355ef3166eSFrederic Barrat }
4365ef3166eSFrederic Barrat afu->name[OCXL_AFU_NAME_SZ - 1] = '\0'; /* play safe */
4375ef3166eSFrederic Barrat return 0;
4385ef3166eSFrederic Barrat }
4395ef3166eSFrederic Barrat
read_afu_mmio(struct pci_dev * dev,struct ocxl_fn_config * fn,struct ocxl_afu_config * afu)4405ef3166eSFrederic Barrat static int read_afu_mmio(struct pci_dev *dev, struct ocxl_fn_config *fn,
4415ef3166eSFrederic Barrat struct ocxl_afu_config *afu)
4425ef3166eSFrederic Barrat {
4435ef3166eSFrederic Barrat int rc;
4445ef3166eSFrederic Barrat u32 val;
4455ef3166eSFrederic Barrat
4465ef3166eSFrederic Barrat /*
4475ef3166eSFrederic Barrat * Global MMIO
4485ef3166eSFrederic Barrat */
4495ef3166eSFrederic Barrat rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_MMIO_GLOBAL, &val);
4505ef3166eSFrederic Barrat if (rc)
4515ef3166eSFrederic Barrat return rc;
4525ef3166eSFrederic Barrat afu->global_mmio_bar = EXTRACT_BITS(val, 0, 2);
4535ef3166eSFrederic Barrat afu->global_mmio_offset = EXTRACT_BITS(val, 16, 31) << 16;
4545ef3166eSFrederic Barrat
4555ef3166eSFrederic Barrat rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_MMIO_GLOBAL + 4, &val);
4565ef3166eSFrederic Barrat if (rc)
4575ef3166eSFrederic Barrat return rc;
4585ef3166eSFrederic Barrat afu->global_mmio_offset += (u64) val << 32;
4595ef3166eSFrederic Barrat
4605ef3166eSFrederic Barrat rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_MMIO_GLOBAL_SZ, &val);
4615ef3166eSFrederic Barrat if (rc)
4625ef3166eSFrederic Barrat return rc;
4635ef3166eSFrederic Barrat afu->global_mmio_size = val;
4645ef3166eSFrederic Barrat
4655ef3166eSFrederic Barrat /*
4665ef3166eSFrederic Barrat * Per-process MMIO
4675ef3166eSFrederic Barrat */
4685ef3166eSFrederic Barrat rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_MMIO_PP, &val);
4695ef3166eSFrederic Barrat if (rc)
4705ef3166eSFrederic Barrat return rc;
4715ef3166eSFrederic Barrat afu->pp_mmio_bar = EXTRACT_BITS(val, 0, 2);
4725ef3166eSFrederic Barrat afu->pp_mmio_offset = EXTRACT_BITS(val, 16, 31) << 16;
4735ef3166eSFrederic Barrat
4745ef3166eSFrederic Barrat rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_MMIO_PP + 4, &val);
4755ef3166eSFrederic Barrat if (rc)
4765ef3166eSFrederic Barrat return rc;
4775ef3166eSFrederic Barrat afu->pp_mmio_offset += (u64) val << 32;
4785ef3166eSFrederic Barrat
4795ef3166eSFrederic Barrat rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_MMIO_PP_SZ, &val);
4805ef3166eSFrederic Barrat if (rc)
4815ef3166eSFrederic Barrat return rc;
4825ef3166eSFrederic Barrat afu->pp_mmio_stride = val;
4835ef3166eSFrederic Barrat
4845ef3166eSFrederic Barrat return 0;
4855ef3166eSFrederic Barrat }
4865ef3166eSFrederic Barrat
read_afu_control(struct pci_dev * dev,struct ocxl_afu_config * afu)4875ef3166eSFrederic Barrat static int read_afu_control(struct pci_dev *dev, struct ocxl_afu_config *afu)
4885ef3166eSFrederic Barrat {
4895ef3166eSFrederic Barrat int pos;
4905ef3166eSFrederic Barrat u8 val8;
4915ef3166eSFrederic Barrat u16 val16;
4925ef3166eSFrederic Barrat
4935ef3166eSFrederic Barrat pos = find_dvsec_afu_ctrl(dev, afu->idx);
4945ef3166eSFrederic Barrat if (!pos) {
4955ef3166eSFrederic Barrat dev_err(&dev->dev, "Can't find AFU control DVSEC for AFU %d\n",
4965ef3166eSFrederic Barrat afu->idx);
4975ef3166eSFrederic Barrat return -ENODEV;
4985ef3166eSFrederic Barrat }
4995ef3166eSFrederic Barrat afu->dvsec_afu_control_pos = pos;
5005ef3166eSFrederic Barrat
5015ef3166eSFrederic Barrat pci_read_config_byte(dev, pos + OCXL_DVSEC_AFU_CTRL_PASID_SUP, &val8);
5025ef3166eSFrederic Barrat afu->pasid_supported_log = EXTRACT_BITS(val8, 0, 4);
5035ef3166eSFrederic Barrat
5045ef3166eSFrederic Barrat pci_read_config_word(dev, pos + OCXL_DVSEC_AFU_CTRL_ACTAG_SUP, &val16);
5055ef3166eSFrederic Barrat afu->actag_supported = EXTRACT_BITS(val16, 0, 11);
5065ef3166eSFrederic Barrat return 0;
5075ef3166eSFrederic Barrat }
5085ef3166eSFrederic Barrat
char_allowed(int c)5095ef3166eSFrederic Barrat static bool char_allowed(int c)
5105ef3166eSFrederic Barrat {
5115ef3166eSFrederic Barrat /*
5125ef3166eSFrederic Barrat * Permitted Characters : Alphanumeric, hyphen, underscore, comma
5135ef3166eSFrederic Barrat */
5145ef3166eSFrederic Barrat if ((c >= 0x30 && c <= 0x39) /* digits */ ||
5155ef3166eSFrederic Barrat (c >= 0x41 && c <= 0x5A) /* upper case */ ||
5165ef3166eSFrederic Barrat (c >= 0x61 && c <= 0x7A) /* lower case */ ||
5175ef3166eSFrederic Barrat c == 0 /* NULL */ ||
5185ef3166eSFrederic Barrat c == 0x2D /* - */ ||
5195ef3166eSFrederic Barrat c == 0x5F /* _ */ ||
5205ef3166eSFrederic Barrat c == 0x2C /* , */)
5215ef3166eSFrederic Barrat return true;
5225ef3166eSFrederic Barrat return false;
5235ef3166eSFrederic Barrat }
5245ef3166eSFrederic Barrat
validate_afu(struct pci_dev * dev,struct ocxl_afu_config * afu)5255ef3166eSFrederic Barrat static int validate_afu(struct pci_dev *dev, struct ocxl_afu_config *afu)
5265ef3166eSFrederic Barrat {
5275ef3166eSFrederic Barrat int i;
5285ef3166eSFrederic Barrat
5295ef3166eSFrederic Barrat if (!afu->name[0]) {
5305ef3166eSFrederic Barrat dev_err(&dev->dev, "Empty AFU name\n");
5315ef3166eSFrederic Barrat return -EINVAL;
5325ef3166eSFrederic Barrat }
5335ef3166eSFrederic Barrat for (i = 0; i < OCXL_TEMPL_NAME_LEN; i++) {
5345ef3166eSFrederic Barrat if (!char_allowed(afu->name[i])) {
5355ef3166eSFrederic Barrat dev_err(&dev->dev,
5365ef3166eSFrederic Barrat "Invalid character in AFU name\n");
5375ef3166eSFrederic Barrat return -EINVAL;
5385ef3166eSFrederic Barrat }
5395ef3166eSFrederic Barrat }
5405ef3166eSFrederic Barrat
5415ef3166eSFrederic Barrat if (afu->global_mmio_bar != 0 &&
5425ef3166eSFrederic Barrat afu->global_mmio_bar != 2 &&
5435ef3166eSFrederic Barrat afu->global_mmio_bar != 4) {
5445ef3166eSFrederic Barrat dev_err(&dev->dev, "Invalid global MMIO bar number\n");
5455ef3166eSFrederic Barrat return -EINVAL;
5465ef3166eSFrederic Barrat }
5475ef3166eSFrederic Barrat if (afu->pp_mmio_bar != 0 &&
5485ef3166eSFrederic Barrat afu->pp_mmio_bar != 2 &&
5495ef3166eSFrederic Barrat afu->pp_mmio_bar != 4) {
5505ef3166eSFrederic Barrat dev_err(&dev->dev, "Invalid per-process MMIO bar number\n");
5515ef3166eSFrederic Barrat return -EINVAL;
5525ef3166eSFrederic Barrat }
5535ef3166eSFrederic Barrat return 0;
5545ef3166eSFrederic Barrat }
5555ef3166eSFrederic Barrat
55673a2b047SAlastair D'Silva /**
5573591538aSAlastair D'Silva * read_afu_lpc_memory_info() - Populate AFU metadata regarding LPC memory
5583591538aSAlastair D'Silva * @dev: the device for the AFU
5593591538aSAlastair D'Silva * @fn: the AFU offsets
5603591538aSAlastair D'Silva * @afu: the AFU struct to populate the LPC metadata into
56173a2b047SAlastair D'Silva *
56273a2b047SAlastair D'Silva * Returns 0 on success, negative on failure
56373a2b047SAlastair D'Silva */
read_afu_lpc_memory_info(struct pci_dev * dev,struct ocxl_fn_config * fn,struct ocxl_afu_config * afu)56473a2b047SAlastair D'Silva static int read_afu_lpc_memory_info(struct pci_dev *dev,
56573a2b047SAlastair D'Silva struct ocxl_fn_config *fn,
56673a2b047SAlastair D'Silva struct ocxl_afu_config *afu)
56773a2b047SAlastair D'Silva {
56873a2b047SAlastair D'Silva int rc;
56973a2b047SAlastair D'Silva u32 val32;
57073a2b047SAlastair D'Silva u16 templ_version;
57173a2b047SAlastair D'Silva u16 templ_len;
57273a2b047SAlastair D'Silva u64 total_mem_size = 0;
57373a2b047SAlastair D'Silva u64 lpc_mem_size = 0;
57473a2b047SAlastair D'Silva
57573a2b047SAlastair D'Silva afu->lpc_mem_offset = 0;
57673a2b047SAlastair D'Silva afu->lpc_mem_size = 0;
57773a2b047SAlastair D'Silva afu->special_purpose_mem_offset = 0;
57873a2b047SAlastair D'Silva afu->special_purpose_mem_size = 0;
57973a2b047SAlastair D'Silva /*
58073a2b047SAlastair D'Silva * For AFUs following template v1.0, the LPC memory covers the
58173a2b047SAlastair D'Silva * total memory. Its size is a power of 2.
58273a2b047SAlastair D'Silva *
58373a2b047SAlastair D'Silva * For AFUs with template >= v1.01, the total memory size is
58473a2b047SAlastair D'Silva * still a power of 2, but it is split in 2 parts:
58573a2b047SAlastair D'Silva * - the LPC memory, whose size can now be anything
58673a2b047SAlastair D'Silva * - the remainder memory is a special purpose memory, whose
58773a2b047SAlastair D'Silva * definition is AFU-dependent. It is not accessible through
58873a2b047SAlastair D'Silva * the usual commands for LPC memory
58973a2b047SAlastair D'Silva */
59073a2b047SAlastair D'Silva rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_ALL_MEM_SZ, &val32);
59173a2b047SAlastair D'Silva if (rc)
59273a2b047SAlastair D'Silva return rc;
59373a2b047SAlastair D'Silva
59473a2b047SAlastair D'Silva val32 = EXTRACT_BITS(val32, 0, 7);
59573a2b047SAlastair D'Silva if (!val32)
59673a2b047SAlastair D'Silva return 0; /* No LPC memory */
59773a2b047SAlastair D'Silva
59873a2b047SAlastair D'Silva /*
59973a2b047SAlastair D'Silva * The configuration space spec allows for a memory size of up
60073a2b047SAlastair D'Silva * to 2^255 bytes.
60173a2b047SAlastair D'Silva *
60273a2b047SAlastair D'Silva * Current generation hardware uses 56-bit physical addresses,
60373a2b047SAlastair D'Silva * but we won't be able to get near close to that, as we won't
60473a2b047SAlastair D'Silva * have a hole big enough in the memory map. Let it pass in
60573a2b047SAlastair D'Silva * the driver for now. We'll get an error from the firmware
60673a2b047SAlastair D'Silva * when trying to configure something too big.
60773a2b047SAlastair D'Silva */
60873a2b047SAlastair D'Silva total_mem_size = 1ull << val32;
60973a2b047SAlastair D'Silva
61073a2b047SAlastair D'Silva rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_LPC_MEM_START, &val32);
61173a2b047SAlastair D'Silva if (rc)
61273a2b047SAlastair D'Silva return rc;
61373a2b047SAlastair D'Silva
61473a2b047SAlastair D'Silva afu->lpc_mem_offset = val32;
61573a2b047SAlastair D'Silva
61673a2b047SAlastair D'Silva rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_LPC_MEM_START + 4, &val32);
61773a2b047SAlastair D'Silva if (rc)
61873a2b047SAlastair D'Silva return rc;
61973a2b047SAlastair D'Silva
62073a2b047SAlastair D'Silva afu->lpc_mem_offset |= (u64) val32 << 32;
62173a2b047SAlastair D'Silva
62273a2b047SAlastair D'Silva rc = read_template_version(dev, fn, &templ_len, &templ_version);
62373a2b047SAlastair D'Silva if (rc)
62473a2b047SAlastair D'Silva return rc;
62573a2b047SAlastair D'Silva
62673a2b047SAlastair D'Silva if (templ_version >= 0x0101) {
62773a2b047SAlastair D'Silva rc = read_afu_info(dev, fn,
62873a2b047SAlastair D'Silva OCXL_DVSEC_TEMPL_LPC_MEM_SZ, &val32);
62973a2b047SAlastair D'Silva if (rc)
63073a2b047SAlastair D'Silva return rc;
63173a2b047SAlastair D'Silva lpc_mem_size = val32;
63273a2b047SAlastair D'Silva
63373a2b047SAlastair D'Silva rc = read_afu_info(dev, fn,
63473a2b047SAlastair D'Silva OCXL_DVSEC_TEMPL_LPC_MEM_SZ + 4, &val32);
63573a2b047SAlastair D'Silva if (rc)
63673a2b047SAlastair D'Silva return rc;
63773a2b047SAlastair D'Silva lpc_mem_size |= (u64) val32 << 32;
63873a2b047SAlastair D'Silva } else {
63973a2b047SAlastair D'Silva lpc_mem_size = total_mem_size;
64073a2b047SAlastair D'Silva }
64173a2b047SAlastair D'Silva afu->lpc_mem_size = lpc_mem_size;
64273a2b047SAlastair D'Silva
64373a2b047SAlastair D'Silva if (lpc_mem_size < total_mem_size) {
64473a2b047SAlastair D'Silva afu->special_purpose_mem_offset =
64573a2b047SAlastair D'Silva afu->lpc_mem_offset + lpc_mem_size;
64673a2b047SAlastair D'Silva afu->special_purpose_mem_size =
64773a2b047SAlastair D'Silva total_mem_size - lpc_mem_size;
64873a2b047SAlastair D'Silva }
64973a2b047SAlastair D'Silva return 0;
65073a2b047SAlastair D'Silva }
65173a2b047SAlastair D'Silva
ocxl_config_read_afu(struct pci_dev * dev,struct ocxl_fn_config * fn,struct ocxl_afu_config * afu,u8 afu_idx)6525ef3166eSFrederic Barrat int ocxl_config_read_afu(struct pci_dev *dev, struct ocxl_fn_config *fn,
6535ef3166eSFrederic Barrat struct ocxl_afu_config *afu, u8 afu_idx)
6545ef3166eSFrederic Barrat {
6555ef3166eSFrederic Barrat int rc;
6565ef3166eSFrederic Barrat u32 val32;
6575ef3166eSFrederic Barrat
6585ef3166eSFrederic Barrat /*
6595ef3166eSFrederic Barrat * First, we need to write the AFU idx for the AFU we want to
6605ef3166eSFrederic Barrat * access.
6615ef3166eSFrederic Barrat */
6625ef3166eSFrederic Barrat WARN_ON((afu_idx & OCXL_DVSEC_AFU_IDX_MASK) != afu_idx);
6635ef3166eSFrederic Barrat afu->idx = afu_idx;
6645ef3166eSFrederic Barrat pci_write_config_byte(dev,
6655ef3166eSFrederic Barrat fn->dvsec_afu_info_pos + OCXL_DVSEC_AFU_INFO_AFU_IDX,
6665ef3166eSFrederic Barrat afu->idx);
6675ef3166eSFrederic Barrat
6685ef3166eSFrederic Barrat rc = read_afu_name(dev, fn, afu);
6695ef3166eSFrederic Barrat if (rc)
6705ef3166eSFrederic Barrat return rc;
6715ef3166eSFrederic Barrat
6725ef3166eSFrederic Barrat rc = read_afu_info(dev, fn, OCXL_DVSEC_TEMPL_AFU_VERSION, &val32);
6735ef3166eSFrederic Barrat if (rc)
6745ef3166eSFrederic Barrat return rc;
6755ef3166eSFrederic Barrat afu->version_major = EXTRACT_BITS(val32, 24, 31);
6765ef3166eSFrederic Barrat afu->version_minor = EXTRACT_BITS(val32, 16, 23);
6775ef3166eSFrederic Barrat afu->afuc_type = EXTRACT_BITS(val32, 14, 15);
6785ef3166eSFrederic Barrat afu->afum_type = EXTRACT_BITS(val32, 12, 13);
6795ef3166eSFrederic Barrat afu->profile = EXTRACT_BITS(val32, 0, 7);
6805ef3166eSFrederic Barrat
6815ef3166eSFrederic Barrat rc = read_afu_mmio(dev, fn, afu);
6825ef3166eSFrederic Barrat if (rc)
6835ef3166eSFrederic Barrat return rc;
6845ef3166eSFrederic Barrat
68573a2b047SAlastair D'Silva rc = read_afu_lpc_memory_info(dev, fn, afu);
6865ef3166eSFrederic Barrat if (rc)
6875ef3166eSFrederic Barrat return rc;
6885ef3166eSFrederic Barrat
6895ef3166eSFrederic Barrat rc = read_afu_control(dev, afu);
6905ef3166eSFrederic Barrat if (rc)
6915ef3166eSFrederic Barrat return rc;
6925ef3166eSFrederic Barrat
6935ef3166eSFrederic Barrat dev_dbg(&dev->dev, "AFU configuration:\n");
6945ef3166eSFrederic Barrat dev_dbg(&dev->dev, " name = %s\n", afu->name);
6955ef3166eSFrederic Barrat dev_dbg(&dev->dev, " version = %d.%d\n", afu->version_major,
6965ef3166eSFrederic Barrat afu->version_minor);
6975ef3166eSFrederic Barrat dev_dbg(&dev->dev, " global mmio bar = %hhu\n", afu->global_mmio_bar);
6985ef3166eSFrederic Barrat dev_dbg(&dev->dev, " global mmio offset = %#llx\n",
6995ef3166eSFrederic Barrat afu->global_mmio_offset);
7005ef3166eSFrederic Barrat dev_dbg(&dev->dev, " global mmio size = %#x\n", afu->global_mmio_size);
7015ef3166eSFrederic Barrat dev_dbg(&dev->dev, " pp mmio bar = %hhu\n", afu->pp_mmio_bar);
7025ef3166eSFrederic Barrat dev_dbg(&dev->dev, " pp mmio offset = %#llx\n", afu->pp_mmio_offset);
7035ef3166eSFrederic Barrat dev_dbg(&dev->dev, " pp mmio stride = %#x\n", afu->pp_mmio_stride);
70473a2b047SAlastair D'Silva dev_dbg(&dev->dev, " lpc_mem offset = %#llx\n", afu->lpc_mem_offset);
70573a2b047SAlastair D'Silva dev_dbg(&dev->dev, " lpc_mem size = %#llx\n", afu->lpc_mem_size);
70673a2b047SAlastair D'Silva dev_dbg(&dev->dev, " special purpose mem offset = %#llx\n",
70773a2b047SAlastair D'Silva afu->special_purpose_mem_offset);
70873a2b047SAlastair D'Silva dev_dbg(&dev->dev, " special purpose mem size = %#llx\n",
70973a2b047SAlastair D'Silva afu->special_purpose_mem_size);
7105ef3166eSFrederic Barrat dev_dbg(&dev->dev, " pasid supported (log) = %u\n",
7115ef3166eSFrederic Barrat afu->pasid_supported_log);
7125ef3166eSFrederic Barrat dev_dbg(&dev->dev, " actag supported = %u\n",
7135ef3166eSFrederic Barrat afu->actag_supported);
7145ef3166eSFrederic Barrat
7155ef3166eSFrederic Barrat rc = validate_afu(dev, afu);
7165ef3166eSFrederic Barrat return rc;
7175ef3166eSFrederic Barrat }
718280b983cSFrederic Barrat EXPORT_SYMBOL_GPL(ocxl_config_read_afu);
7195ef3166eSFrederic Barrat
ocxl_config_get_actag_info(struct pci_dev * dev,u16 * base,u16 * enabled,u16 * supported)7205ef3166eSFrederic Barrat int ocxl_config_get_actag_info(struct pci_dev *dev, u16 *base, u16 *enabled,
7215ef3166eSFrederic Barrat u16 *supported)
7225ef3166eSFrederic Barrat {
7235ef3166eSFrederic Barrat int rc;
7245ef3166eSFrederic Barrat
7255ef3166eSFrederic Barrat /*
7265ef3166eSFrederic Barrat * This is really a simple wrapper for the kernel API, to
7275ef3166eSFrederic Barrat * avoid an external driver using ocxl as a library to call
7285ef3166eSFrederic Barrat * platform-dependent code
7295ef3166eSFrederic Barrat */
7305ef3166eSFrederic Barrat rc = pnv_ocxl_get_actag(dev, base, enabled, supported);
7315ef3166eSFrederic Barrat if (rc) {
7325ef3166eSFrederic Barrat dev_err(&dev->dev, "Can't get actag for device: %d\n", rc);
7335ef3166eSFrederic Barrat return rc;
7345ef3166eSFrederic Barrat }
7355ef3166eSFrederic Barrat return 0;
7365ef3166eSFrederic Barrat }
737280b983cSFrederic Barrat EXPORT_SYMBOL_GPL(ocxl_config_get_actag_info);
7385ef3166eSFrederic Barrat
ocxl_config_set_afu_actag(struct pci_dev * dev,int pos,int actag_base,int actag_count)7395ef3166eSFrederic Barrat void ocxl_config_set_afu_actag(struct pci_dev *dev, int pos, int actag_base,
7405ef3166eSFrederic Barrat int actag_count)
7415ef3166eSFrederic Barrat {
7425ef3166eSFrederic Barrat u16 val;
7435ef3166eSFrederic Barrat
7445ef3166eSFrederic Barrat val = actag_count & OCXL_DVSEC_ACTAG_MASK;
7455ef3166eSFrederic Barrat pci_write_config_byte(dev, pos + OCXL_DVSEC_AFU_CTRL_ACTAG_EN, val);
7465ef3166eSFrederic Barrat
7475ef3166eSFrederic Barrat val = actag_base & OCXL_DVSEC_ACTAG_MASK;
7485ef3166eSFrederic Barrat pci_write_config_dword(dev, pos + OCXL_DVSEC_AFU_CTRL_ACTAG_BASE, val);
7495ef3166eSFrederic Barrat }
750280b983cSFrederic Barrat EXPORT_SYMBOL_GPL(ocxl_config_set_afu_actag);
7515ef3166eSFrederic Barrat
ocxl_config_get_pasid_info(struct pci_dev * dev,int * count)7525ef3166eSFrederic Barrat int ocxl_config_get_pasid_info(struct pci_dev *dev, int *count)
7535ef3166eSFrederic Barrat {
7545ef3166eSFrederic Barrat return pnv_ocxl_get_pasid_count(dev, count);
7555ef3166eSFrederic Barrat }
7565ef3166eSFrederic Barrat
ocxl_config_set_afu_pasid(struct pci_dev * dev,int pos,int pasid_base,u32 pasid_count_log)7575ef3166eSFrederic Barrat void ocxl_config_set_afu_pasid(struct pci_dev *dev, int pos, int pasid_base,
7585ef3166eSFrederic Barrat u32 pasid_count_log)
7595ef3166eSFrederic Barrat {
7605ef3166eSFrederic Barrat u8 val8;
7615ef3166eSFrederic Barrat u32 val32;
7625ef3166eSFrederic Barrat
7635ef3166eSFrederic Barrat val8 = pasid_count_log & OCXL_DVSEC_PASID_LOG_MASK;
7645ef3166eSFrederic Barrat pci_write_config_byte(dev, pos + OCXL_DVSEC_AFU_CTRL_PASID_EN, val8);
7655ef3166eSFrederic Barrat
7665ef3166eSFrederic Barrat pci_read_config_dword(dev, pos + OCXL_DVSEC_AFU_CTRL_PASID_BASE,
7675ef3166eSFrederic Barrat &val32);
7685ef3166eSFrederic Barrat val32 &= ~OCXL_DVSEC_PASID_MASK;
7695ef3166eSFrederic Barrat val32 |= pasid_base & OCXL_DVSEC_PASID_MASK;
7705ef3166eSFrederic Barrat pci_write_config_dword(dev, pos + OCXL_DVSEC_AFU_CTRL_PASID_BASE,
7715ef3166eSFrederic Barrat val32);
7725ef3166eSFrederic Barrat }
773280b983cSFrederic Barrat EXPORT_SYMBOL_GPL(ocxl_config_set_afu_pasid);
7745ef3166eSFrederic Barrat
ocxl_config_set_afu_state(struct pci_dev * dev,int pos,int enable)7755ef3166eSFrederic Barrat void ocxl_config_set_afu_state(struct pci_dev *dev, int pos, int enable)
7765ef3166eSFrederic Barrat {
7775ef3166eSFrederic Barrat u8 val;
7785ef3166eSFrederic Barrat
7795ef3166eSFrederic Barrat pci_read_config_byte(dev, pos + OCXL_DVSEC_AFU_CTRL_ENABLE, &val);
7805ef3166eSFrederic Barrat if (enable)
7815ef3166eSFrederic Barrat val |= 1;
7825ef3166eSFrederic Barrat else
7835ef3166eSFrederic Barrat val &= 0xFE;
7845ef3166eSFrederic Barrat pci_write_config_byte(dev, pos + OCXL_DVSEC_AFU_CTRL_ENABLE, val);
7855ef3166eSFrederic Barrat }
786280b983cSFrederic Barrat EXPORT_SYMBOL_GPL(ocxl_config_set_afu_state);
7875ef3166eSFrederic Barrat
ocxl_config_set_TL(struct pci_dev * dev,int tl_dvsec)7885ef3166eSFrederic Barrat int ocxl_config_set_TL(struct pci_dev *dev, int tl_dvsec)
7895ef3166eSFrederic Barrat {
7905ef3166eSFrederic Barrat u32 val;
7915ef3166eSFrederic Barrat __be32 *be32ptr;
7925ef3166eSFrederic Barrat u8 timers;
7935ef3166eSFrederic Barrat int i, rc;
7945ef3166eSFrederic Barrat long recv_cap;
7955ef3166eSFrederic Barrat char *recv_rate;
7965ef3166eSFrederic Barrat
7975ef3166eSFrederic Barrat /*
7985ef3166eSFrederic Barrat * Skip on function != 0, as the TL can only be defined on 0
7995ef3166eSFrederic Barrat */
8005ef3166eSFrederic Barrat if (PCI_FUNC(dev->devfn) != 0)
8015ef3166eSFrederic Barrat return 0;
8025ef3166eSFrederic Barrat
8035ef3166eSFrederic Barrat recv_rate = kzalloc(PNV_OCXL_TL_RATE_BUF_SIZE, GFP_KERNEL);
8045ef3166eSFrederic Barrat if (!recv_rate)
8055ef3166eSFrederic Barrat return -ENOMEM;
8065ef3166eSFrederic Barrat /*
8075ef3166eSFrederic Barrat * The spec defines 64 templates for messages in the
8085ef3166eSFrederic Barrat * Transaction Layer (TL).
8095ef3166eSFrederic Barrat *
8105ef3166eSFrederic Barrat * The host and device each support a subset, so we need to
8115ef3166eSFrederic Barrat * configure the transmitters on each side to send only
8125ef3166eSFrederic Barrat * templates the receiver understands, at a rate the receiver
8135ef3166eSFrederic Barrat * can process. Per the spec, template 0 must be supported by
8145ef3166eSFrederic Barrat * everybody. That's the template which has been used by the
8155ef3166eSFrederic Barrat * host and device so far.
8165ef3166eSFrederic Barrat *
8175ef3166eSFrederic Barrat * The sending rate limit must be set before the template is
8185ef3166eSFrederic Barrat * enabled.
8195ef3166eSFrederic Barrat */
8205ef3166eSFrederic Barrat
8215ef3166eSFrederic Barrat /*
8225ef3166eSFrederic Barrat * Device -> host
8235ef3166eSFrederic Barrat */
8245ef3166eSFrederic Barrat rc = pnv_ocxl_get_tl_cap(dev, &recv_cap, recv_rate,
8255ef3166eSFrederic Barrat PNV_OCXL_TL_RATE_BUF_SIZE);
8265ef3166eSFrederic Barrat if (rc)
8275ef3166eSFrederic Barrat goto out;
8285ef3166eSFrederic Barrat
8295ef3166eSFrederic Barrat for (i = 0; i < PNV_OCXL_TL_RATE_BUF_SIZE; i += 4) {
8305ef3166eSFrederic Barrat be32ptr = (__be32 *) &recv_rate[i];
8315ef3166eSFrederic Barrat pci_write_config_dword(dev,
8325ef3166eSFrederic Barrat tl_dvsec + OCXL_DVSEC_TL_SEND_RATE + i,
8335ef3166eSFrederic Barrat be32_to_cpu(*be32ptr));
8345ef3166eSFrederic Barrat }
8355ef3166eSFrederic Barrat val = recv_cap >> 32;
8365ef3166eSFrederic Barrat pci_write_config_dword(dev, tl_dvsec + OCXL_DVSEC_TL_SEND_CAP, val);
8375ef3166eSFrederic Barrat val = recv_cap & GENMASK(31, 0);
8385ef3166eSFrederic Barrat pci_write_config_dword(dev, tl_dvsec + OCXL_DVSEC_TL_SEND_CAP + 4, val);
8395ef3166eSFrederic Barrat
8405ef3166eSFrederic Barrat /*
8415ef3166eSFrederic Barrat * Host -> device
8425ef3166eSFrederic Barrat */
8435ef3166eSFrederic Barrat for (i = 0; i < PNV_OCXL_TL_RATE_BUF_SIZE; i += 4) {
8445ef3166eSFrederic Barrat pci_read_config_dword(dev,
8455ef3166eSFrederic Barrat tl_dvsec + OCXL_DVSEC_TL_RECV_RATE + i,
8465ef3166eSFrederic Barrat &val);
8475ef3166eSFrederic Barrat be32ptr = (__be32 *) &recv_rate[i];
8485ef3166eSFrederic Barrat *be32ptr = cpu_to_be32(val);
8495ef3166eSFrederic Barrat }
8505ef3166eSFrederic Barrat pci_read_config_dword(dev, tl_dvsec + OCXL_DVSEC_TL_RECV_CAP, &val);
8515ef3166eSFrederic Barrat recv_cap = (long) val << 32;
8525ef3166eSFrederic Barrat pci_read_config_dword(dev, tl_dvsec + OCXL_DVSEC_TL_RECV_CAP + 4, &val);
8535ef3166eSFrederic Barrat recv_cap |= val;
8545ef3166eSFrederic Barrat
8555ef3166eSFrederic Barrat rc = pnv_ocxl_set_tl_conf(dev, recv_cap, __pa(recv_rate),
8565ef3166eSFrederic Barrat PNV_OCXL_TL_RATE_BUF_SIZE);
8575ef3166eSFrederic Barrat if (rc)
8585ef3166eSFrederic Barrat goto out;
8595ef3166eSFrederic Barrat
8605ef3166eSFrederic Barrat /*
8615ef3166eSFrederic Barrat * Opencapi commands needing to be retried are classified per
8625ef3166eSFrederic Barrat * the TL in 2 groups: short and long commands.
8635ef3166eSFrederic Barrat *
8645ef3166eSFrederic Barrat * The short back off timer it not used for now. It will be
8655ef3166eSFrederic Barrat * for opencapi 4.0.
8665ef3166eSFrederic Barrat *
8675ef3166eSFrederic Barrat * The long back off timer is typically used when an AFU hits
8685ef3166eSFrederic Barrat * a page fault but the NPU is already processing one. So the
8695ef3166eSFrederic Barrat * AFU needs to wait before it can resubmit. Having a value
8705ef3166eSFrederic Barrat * too low doesn't break anything, but can generate extra
8715ef3166eSFrederic Barrat * traffic on the link.
8725ef3166eSFrederic Barrat * We set it to 1.6 us for now. It's shorter than, but in the
8735ef3166eSFrederic Barrat * same order of magnitude as the time spent to process a page
8745ef3166eSFrederic Barrat * fault.
8755ef3166eSFrederic Barrat */
8765ef3166eSFrederic Barrat timers = 0x2 << 4; /* long timer = 1.6 us */
8775ef3166eSFrederic Barrat pci_write_config_byte(dev, tl_dvsec + OCXL_DVSEC_TL_BACKOFF_TIMERS,
8785ef3166eSFrederic Barrat timers);
8795ef3166eSFrederic Barrat
8805ef3166eSFrederic Barrat rc = 0;
8815ef3166eSFrederic Barrat out:
8825ef3166eSFrederic Barrat kfree(recv_rate);
8835ef3166eSFrederic Barrat return rc;
8845ef3166eSFrederic Barrat }
885280b983cSFrederic Barrat EXPORT_SYMBOL_GPL(ocxl_config_set_TL);
8865ef3166eSFrederic Barrat
ocxl_config_terminate_pasid(struct pci_dev * dev,int afu_control,int pasid)8875ef3166eSFrederic Barrat int ocxl_config_terminate_pasid(struct pci_dev *dev, int afu_control, int pasid)
8885ef3166eSFrederic Barrat {
8895ef3166eSFrederic Barrat u32 val;
8905ef3166eSFrederic Barrat unsigned long timeout;
8915ef3166eSFrederic Barrat
8925ef3166eSFrederic Barrat pci_read_config_dword(dev, afu_control + OCXL_DVSEC_AFU_CTRL_TERM_PASID,
8935ef3166eSFrederic Barrat &val);
8945ef3166eSFrederic Barrat if (EXTRACT_BIT(val, 20)) {
8955ef3166eSFrederic Barrat dev_err(&dev->dev,
8965ef3166eSFrederic Barrat "Can't terminate PASID %#x, previous termination didn't complete\n",
8975ef3166eSFrederic Barrat pasid);
8985ef3166eSFrederic Barrat return -EBUSY;
8995ef3166eSFrederic Barrat }
9005ef3166eSFrederic Barrat
9015ef3166eSFrederic Barrat val &= ~OCXL_DVSEC_PASID_MASK;
9025ef3166eSFrederic Barrat val |= pasid & OCXL_DVSEC_PASID_MASK;
9035ef3166eSFrederic Barrat val |= BIT(20);
9045ef3166eSFrederic Barrat pci_write_config_dword(dev,
9055ef3166eSFrederic Barrat afu_control + OCXL_DVSEC_AFU_CTRL_TERM_PASID,
9065ef3166eSFrederic Barrat val);
9075ef3166eSFrederic Barrat
9085ef3166eSFrederic Barrat timeout = jiffies + (HZ * OCXL_CFG_TIMEOUT);
9095ef3166eSFrederic Barrat pci_read_config_dword(dev, afu_control + OCXL_DVSEC_AFU_CTRL_TERM_PASID,
9105ef3166eSFrederic Barrat &val);
9115ef3166eSFrederic Barrat while (EXTRACT_BIT(val, 20)) {
9125ef3166eSFrederic Barrat if (time_after_eq(jiffies, timeout)) {
9135ef3166eSFrederic Barrat dev_err(&dev->dev,
9145ef3166eSFrederic Barrat "Timeout while waiting for AFU to terminate PASID %#x\n",
9155ef3166eSFrederic Barrat pasid);
9165ef3166eSFrederic Barrat return -EBUSY;
9175ef3166eSFrederic Barrat }
9185ef3166eSFrederic Barrat cpu_relax();
9195ef3166eSFrederic Barrat pci_read_config_dword(dev,
9205ef3166eSFrederic Barrat afu_control + OCXL_DVSEC_AFU_CTRL_TERM_PASID,
9215ef3166eSFrederic Barrat &val);
9225ef3166eSFrederic Barrat }
9235ef3166eSFrederic Barrat return 0;
9245ef3166eSFrederic Barrat }
925280b983cSFrederic Barrat EXPORT_SYMBOL_GPL(ocxl_config_terminate_pasid);
9265ef3166eSFrederic Barrat
ocxl_config_set_actag(struct pci_dev * dev,int func_dvsec,u32 tag_first,u32 tag_count)9275ef3166eSFrederic Barrat void ocxl_config_set_actag(struct pci_dev *dev, int func_dvsec, u32 tag_first,
9285ef3166eSFrederic Barrat u32 tag_count)
9295ef3166eSFrederic Barrat {
9305ef3166eSFrederic Barrat u32 val;
9315ef3166eSFrederic Barrat
9325ef3166eSFrederic Barrat val = (tag_first & OCXL_DVSEC_ACTAG_MASK) << 16;
9335ef3166eSFrederic Barrat val |= tag_count & OCXL_DVSEC_ACTAG_MASK;
9345ef3166eSFrederic Barrat pci_write_config_dword(dev, func_dvsec + OCXL_DVSEC_FUNC_OFF_ACTAG,
9355ef3166eSFrederic Barrat val);
9365ef3166eSFrederic Barrat }
937280b983cSFrederic Barrat EXPORT_SYMBOL_GPL(ocxl_config_set_actag);
938