1 | // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) |
2 | /* Copyright (C) 2015-2017 Netronome Systems, Inc. */ |
3 | |
4 | /* |
5 | * nfp_mip.c |
6 | * Authors: Jakub Kicinski <jakub.kicinski@netronome.com> |
7 | * Jason McMullan <jason.mcmullan@netronome.com> |
8 | * Espen Skoglund <espen.skoglund@netronome.com> |
9 | */ |
10 | #include <linux/kernel.h> |
11 | #include <linux/slab.h> |
12 | |
13 | #include "nfp.h" |
14 | #include "nfp_cpp.h" |
15 | #include "nfp_nffw.h" |
16 | |
17 | #define NFP_MIP_SIGNATURE cpu_to_le32(0x0050494d) /* "MIP\0" */ |
18 | #define NFP_MIP_VERSION cpu_to_le32(1) |
19 | #define NFP_MIP_MAX_OFFSET (256 * 1024) |
20 | |
21 | struct nfp_mip { |
22 | __le32 signature; |
23 | __le32 mip_version; |
24 | __le32 mip_size; |
25 | __le32 first_entry; |
26 | |
27 | __le32 version; |
28 | __le32 buildnum; |
29 | __le32 buildtime; |
30 | __le32 loadtime; |
31 | |
32 | __le32 symtab_addr; |
33 | __le32 symtab_size; |
34 | __le32 strtab_addr; |
35 | __le32 strtab_size; |
36 | |
37 | char name[16]; |
38 | char toolchain[32]; |
39 | }; |
40 | |
41 | /* Read memory and check if it could be a valid MIP */ |
42 | static int |
43 | nfp_mip_try_read(struct nfp_cpp *cpp, u32 cpp_id, u64 addr, struct nfp_mip *mip) |
44 | { |
45 | int ret; |
46 | |
47 | ret = nfp_cpp_read(cpp, cpp_id, address: addr, kernel_vaddr: mip, length: sizeof(*mip)); |
48 | if (ret != sizeof(*mip)) { |
49 | nfp_err(cpp, "Failed to read MIP data (%d, %zu)\n" , |
50 | ret, sizeof(*mip)); |
51 | return -EIO; |
52 | } |
53 | if (mip->signature != NFP_MIP_SIGNATURE) { |
54 | nfp_warn(cpp, "Incorrect MIP signature (0x%08x)\n" , |
55 | le32_to_cpu(mip->signature)); |
56 | return -EINVAL; |
57 | } |
58 | if (mip->mip_version != NFP_MIP_VERSION) { |
59 | nfp_warn(cpp, "Unsupported MIP version (%d)\n" , |
60 | le32_to_cpu(mip->mip_version)); |
61 | return -EINVAL; |
62 | } |
63 | |
64 | return 0; |
65 | } |
66 | |
67 | /* Try to locate MIP using the resource table */ |
68 | static int nfp_mip_read_resource(struct nfp_cpp *cpp, struct nfp_mip *mip) |
69 | { |
70 | struct nfp_nffw_info *nffw_info; |
71 | u32 cpp_id; |
72 | u64 addr; |
73 | int err; |
74 | |
75 | nffw_info = nfp_nffw_info_open(cpp); |
76 | if (IS_ERR(ptr: nffw_info)) |
77 | return PTR_ERR(ptr: nffw_info); |
78 | |
79 | err = nfp_nffw_info_mip_first(state: nffw_info, cpp_id: &cpp_id, off: &addr); |
80 | if (err) |
81 | goto exit_close_nffw; |
82 | |
83 | err = nfp_mip_try_read(cpp, cpp_id, addr, mip); |
84 | exit_close_nffw: |
85 | nfp_nffw_info_close(state: nffw_info); |
86 | return err; |
87 | } |
88 | |
89 | /** |
90 | * nfp_mip_open() - Get device MIP structure |
91 | * @cpp: NFP CPP Handle |
92 | * |
93 | * Copy MIP structure from NFP device and return it. The returned |
94 | * structure is handled internally by the library and should be |
95 | * freed by calling nfp_mip_close(). |
96 | * |
97 | * Return: pointer to mip, NULL on failure. |
98 | */ |
99 | const struct nfp_mip *nfp_mip_open(struct nfp_cpp *cpp) |
100 | { |
101 | struct nfp_mip *mip; |
102 | int err; |
103 | |
104 | mip = kmalloc(size: sizeof(*mip), GFP_KERNEL); |
105 | if (!mip) |
106 | return NULL; |
107 | |
108 | err = nfp_mip_read_resource(cpp, mip); |
109 | if (err) { |
110 | kfree(objp: mip); |
111 | return NULL; |
112 | } |
113 | |
114 | mip->name[sizeof(mip->name) - 1] = 0; |
115 | |
116 | return mip; |
117 | } |
118 | |
119 | void nfp_mip_close(const struct nfp_mip *mip) |
120 | { |
121 | kfree(objp: mip); |
122 | } |
123 | |
124 | const char *nfp_mip_name(const struct nfp_mip *mip) |
125 | { |
126 | return mip->name; |
127 | } |
128 | |
129 | /** |
130 | * nfp_mip_symtab() - Get the address and size of the MIP symbol table |
131 | * @mip: MIP handle |
132 | * @addr: Location for NFP DDR address of MIP symbol table |
133 | * @size: Location for size of MIP symbol table |
134 | */ |
135 | void nfp_mip_symtab(const struct nfp_mip *mip, u32 *addr, u32 *size) |
136 | { |
137 | *addr = le32_to_cpu(mip->symtab_addr); |
138 | *size = le32_to_cpu(mip->symtab_size); |
139 | } |
140 | |
141 | /** |
142 | * nfp_mip_strtab() - Get the address and size of the MIP symbol name table |
143 | * @mip: MIP handle |
144 | * @addr: Location for NFP DDR address of MIP symbol name table |
145 | * @size: Location for size of MIP symbol name table |
146 | */ |
147 | void nfp_mip_strtab(const struct nfp_mip *mip, u32 *addr, u32 *size) |
148 | { |
149 | *addr = le32_to_cpu(mip->strtab_addr); |
150 | *size = le32_to_cpu(mip->strtab_size); |
151 | } |
152 | |