Skip to content

Commit d2483eb

Browse files
pkwapulianguy11
authored andcommitted
ixgbe: Add support for NVM handling in E610 device
Add low level support for accessing NVM in E610 device. NVM operations are handled via the Admin Command Interface. Add the following NVM specific operations: - acquire, release, read - validate checksum - read shadow ram Co-developed-by: Stefan Wegrzyn <[email protected]> Signed-off-by: Stefan Wegrzyn <[email protected]> Co-developed-by: Jedrzej Jagielski <[email protected]> Signed-off-by: Jedrzej Jagielski <[email protected]> Reviewed-by: Michal Swiatkowski <[email protected]> Reviewed-by: Simon Horman <[email protected]> Tested-by: Bharath R <[email protected]> Signed-off-by: Piotr Kwapulinski <[email protected]> Signed-off-by: Tony Nguyen <[email protected]>
1 parent 23c0e5a commit d2483eb

File tree

2 files changed

+303
-0
lines changed

2 files changed

+303
-0
lines changed

drivers/net/ethernet/intel/ixgbe/ixgbe_e610.c

Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2105,3 +2105,294 @@ int ixgbe_aci_get_netlist_node(struct ixgbe_hw *hw,
21052105

21062106
return 0;
21072107
}
2108+
2109+
/**
2110+
* ixgbe_acquire_nvm - Generic request for acquiring the NVM ownership
2111+
* @hw: pointer to the HW structure
2112+
* @access: NVM access type (read or write)
2113+
*
2114+
* Request NVM ownership.
2115+
*
2116+
* Return: the exit code of the operation.
2117+
*/
2118+
int ixgbe_acquire_nvm(struct ixgbe_hw *hw,
2119+
enum ixgbe_aci_res_access_type access)
2120+
{
2121+
u32 fla;
2122+
2123+
/* Skip if we are in blank NVM programming mode */
2124+
fla = IXGBE_READ_REG(hw, IXGBE_GLNVM_FLA);
2125+
if ((fla & IXGBE_GLNVM_FLA_LOCKED_M) == 0)
2126+
return 0;
2127+
2128+
return ixgbe_acquire_res(hw, IXGBE_NVM_RES_ID, access,
2129+
IXGBE_NVM_TIMEOUT);
2130+
}
2131+
2132+
/**
2133+
* ixgbe_release_nvm - Generic request for releasing the NVM ownership
2134+
* @hw: pointer to the HW structure
2135+
*
2136+
* Release NVM ownership.
2137+
*/
2138+
void ixgbe_release_nvm(struct ixgbe_hw *hw)
2139+
{
2140+
u32 fla;
2141+
2142+
/* Skip if we are in blank NVM programming mode */
2143+
fla = IXGBE_READ_REG(hw, IXGBE_GLNVM_FLA);
2144+
if ((fla & IXGBE_GLNVM_FLA_LOCKED_M) == 0)
2145+
return;
2146+
2147+
ixgbe_release_res(hw, IXGBE_NVM_RES_ID);
2148+
}
2149+
2150+
/**
2151+
* ixgbe_aci_read_nvm - read NVM
2152+
* @hw: pointer to the HW struct
2153+
* @module_typeid: module pointer location in words from the NVM beginning
2154+
* @offset: byte offset from the module beginning
2155+
* @length: length of the section to be read (in bytes from the offset)
2156+
* @data: command buffer (size [bytes] = length)
2157+
* @last_command: tells if this is the last command in a series
2158+
* @read_shadow_ram: tell if this is a shadow RAM read
2159+
*
2160+
* Read the NVM using ACI command (0x0701).
2161+
*
2162+
* Return: the exit code of the operation.
2163+
*/
2164+
int ixgbe_aci_read_nvm(struct ixgbe_hw *hw, u16 module_typeid, u32 offset,
2165+
u16 length, void *data, bool last_command,
2166+
bool read_shadow_ram)
2167+
{
2168+
struct ixgbe_aci_cmd_nvm *cmd;
2169+
struct ixgbe_aci_desc desc;
2170+
2171+
if (offset > IXGBE_ACI_NVM_MAX_OFFSET)
2172+
return -EINVAL;
2173+
2174+
cmd = &desc.params.nvm;
2175+
2176+
ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_nvm_read);
2177+
2178+
if (!read_shadow_ram && module_typeid == IXGBE_ACI_NVM_START_POINT)
2179+
cmd->cmd_flags |= IXGBE_ACI_NVM_FLASH_ONLY;
2180+
2181+
/* If this is the last command in a series, set the proper flag. */
2182+
if (last_command)
2183+
cmd->cmd_flags |= IXGBE_ACI_NVM_LAST_CMD;
2184+
cmd->module_typeid = cpu_to_le16(module_typeid);
2185+
cmd->offset_low = cpu_to_le16(offset & 0xFFFF);
2186+
cmd->offset_high = (offset >> 16) & 0xFF;
2187+
cmd->length = cpu_to_le16(length);
2188+
2189+
return ixgbe_aci_send_cmd(hw, &desc, data, length);
2190+
}
2191+
2192+
/**
2193+
* ixgbe_nvm_validate_checksum - validate checksum
2194+
* @hw: pointer to the HW struct
2195+
*
2196+
* Verify NVM PFA checksum validity using ACI command (0x0706).
2197+
* If the checksum verification failed, IXGBE_ERR_NVM_CHECKSUM is returned.
2198+
* The function acquires and then releases the NVM ownership.
2199+
*
2200+
* Return: the exit code of the operation.
2201+
*/
2202+
int ixgbe_nvm_validate_checksum(struct ixgbe_hw *hw)
2203+
{
2204+
struct ixgbe_aci_cmd_nvm_checksum *cmd;
2205+
struct ixgbe_aci_desc desc;
2206+
int err;
2207+
2208+
err = ixgbe_acquire_nvm(hw, IXGBE_RES_READ);
2209+
if (err)
2210+
return err;
2211+
2212+
cmd = &desc.params.nvm_checksum;
2213+
2214+
ixgbe_fill_dflt_direct_cmd_desc(&desc, ixgbe_aci_opc_nvm_checksum);
2215+
cmd->flags = IXGBE_ACI_NVM_CHECKSUM_VERIFY;
2216+
2217+
err = ixgbe_aci_send_cmd(hw, &desc, NULL, 0);
2218+
2219+
ixgbe_release_nvm(hw);
2220+
2221+
if (!err && cmd->checksum !=
2222+
cpu_to_le16(IXGBE_ACI_NVM_CHECKSUM_CORRECT)) {
2223+
struct ixgbe_adapter *adapter = container_of(hw, struct ixgbe_adapter,
2224+
hw);
2225+
2226+
err = -EIO;
2227+
netdev_err(adapter->netdev, "Invalid Shadow Ram checksum");
2228+
}
2229+
2230+
return err;
2231+
}
2232+
2233+
/**
2234+
* ixgbe_read_sr_word_aci - Reads Shadow RAM via ACI
2235+
* @hw: pointer to the HW structure
2236+
* @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF)
2237+
* @data: word read from the Shadow RAM
2238+
*
2239+
* Reads one 16 bit word from the Shadow RAM using ixgbe_read_flat_nvm.
2240+
*
2241+
* Return: the exit code of the operation.
2242+
*/
2243+
int ixgbe_read_sr_word_aci(struct ixgbe_hw *hw, u16 offset, u16 *data)
2244+
{
2245+
u32 bytes = sizeof(u16);
2246+
u16 data_local;
2247+
int err;
2248+
2249+
err = ixgbe_read_flat_nvm(hw, offset * sizeof(u16), &bytes,
2250+
(u8 *)&data_local, true);
2251+
if (err)
2252+
return err;
2253+
2254+
*data = data_local;
2255+
return 0;
2256+
}
2257+
2258+
/**
2259+
* ixgbe_read_flat_nvm - Read portion of NVM by flat offset
2260+
* @hw: pointer to the HW struct
2261+
* @offset: offset from beginning of NVM
2262+
* @length: (in) number of bytes to read; (out) number of bytes actually read
2263+
* @data: buffer to return data in (sized to fit the specified length)
2264+
* @read_shadow_ram: if true, read from shadow RAM instead of NVM
2265+
*
2266+
* Reads a portion of the NVM, as a flat memory space. This function correctly
2267+
* breaks read requests across Shadow RAM sectors, prevents Shadow RAM size
2268+
* from being exceeded in case of Shadow RAM read requests and ensures that no
2269+
* single read request exceeds the maximum 4KB read for a single admin command.
2270+
*
2271+
* Returns an error code on failure. Note that the data pointer may be
2272+
* partially updated if some reads succeed before a failure.
2273+
*
2274+
* Return: the exit code of the operation.
2275+
*/
2276+
int ixgbe_read_flat_nvm(struct ixgbe_hw *hw, u32 offset, u32 *length,
2277+
u8 *data, bool read_shadow_ram)
2278+
{
2279+
u32 inlen = *length;
2280+
u32 bytes_read = 0;
2281+
bool last_cmd;
2282+
int err;
2283+
2284+
/* Verify the length of the read if this is for the Shadow RAM */
2285+
if (read_shadow_ram && ((offset + inlen) >
2286+
(hw->eeprom.word_size * 2u)))
2287+
return -EINVAL;
2288+
2289+
do {
2290+
u32 read_size, sector_offset;
2291+
2292+
/* ixgbe_aci_read_nvm cannot read more than 4KB at a time.
2293+
* Additionally, a read from the Shadow RAM may not cross over
2294+
* a sector boundary. Conveniently, the sector size is also 4KB.
2295+
*/
2296+
sector_offset = offset % IXGBE_ACI_MAX_BUFFER_SIZE;
2297+
read_size = min_t(u32,
2298+
IXGBE_ACI_MAX_BUFFER_SIZE - sector_offset,
2299+
inlen - bytes_read);
2300+
2301+
last_cmd = !(bytes_read + read_size < inlen);
2302+
2303+
/* ixgbe_aci_read_nvm takes the length as a u16. Our read_size
2304+
* is calculated using a u32, but the IXGBE_ACI_MAX_BUFFER_SIZE
2305+
* maximum size guarantees that it will fit within the 2 bytes.
2306+
*/
2307+
err = ixgbe_aci_read_nvm(hw, IXGBE_ACI_NVM_START_POINT,
2308+
offset, (u16)read_size,
2309+
data + bytes_read, last_cmd,
2310+
read_shadow_ram);
2311+
if (err)
2312+
break;
2313+
2314+
bytes_read += read_size;
2315+
offset += read_size;
2316+
} while (!last_cmd);
2317+
2318+
*length = bytes_read;
2319+
return err;
2320+
}
2321+
2322+
/**
2323+
* ixgbe_read_ee_aci_e610 - Read EEPROM word using the admin command.
2324+
* @hw: pointer to hardware structure
2325+
* @offset: offset of word in the EEPROM to read
2326+
* @data: word read from the EEPROM
2327+
*
2328+
* Reads a 16 bit word from the EEPROM using the ACI.
2329+
* If the EEPROM params are not initialized, the function
2330+
* initialize them before proceeding with reading.
2331+
* The function acquires and then releases the NVM ownership.
2332+
*
2333+
* Return: the exit code of the operation.
2334+
*/
2335+
int ixgbe_read_ee_aci_e610(struct ixgbe_hw *hw, u16 offset, u16 *data)
2336+
{
2337+
int err;
2338+
2339+
if (hw->eeprom.type == ixgbe_eeprom_uninitialized) {
2340+
err = hw->eeprom.ops.init_params(hw);
2341+
if (err)
2342+
return err;
2343+
}
2344+
2345+
err = ixgbe_acquire_nvm(hw, IXGBE_RES_READ);
2346+
if (err)
2347+
return err;
2348+
2349+
err = ixgbe_read_sr_word_aci(hw, offset, data);
2350+
ixgbe_release_nvm(hw);
2351+
2352+
return err;
2353+
}
2354+
2355+
/**
2356+
* ixgbe_validate_eeprom_checksum_e610 - Validate EEPROM checksum
2357+
* @hw: pointer to hardware structure
2358+
* @checksum_val: calculated checksum
2359+
*
2360+
* Performs checksum calculation and validates the EEPROM checksum. If the
2361+
* caller does not need checksum_val, the value can be NULL.
2362+
* If the EEPROM params are not initialized, the function
2363+
* initialize them before proceeding.
2364+
* The function acquires and then releases the NVM ownership.
2365+
*
2366+
* Return: the exit code of the operation.
2367+
*/
2368+
int ixgbe_validate_eeprom_checksum_e610(struct ixgbe_hw *hw, u16 *checksum_val)
2369+
{
2370+
int err;
2371+
2372+
if (hw->eeprom.type == ixgbe_eeprom_uninitialized) {
2373+
err = hw->eeprom.ops.init_params(hw);
2374+
if (err)
2375+
return err;
2376+
}
2377+
2378+
err = ixgbe_nvm_validate_checksum(hw);
2379+
if (err)
2380+
return err;
2381+
2382+
if (checksum_val) {
2383+
u16 tmp_checksum;
2384+
2385+
err = ixgbe_acquire_nvm(hw, IXGBE_RES_READ);
2386+
if (err)
2387+
return err;
2388+
2389+
err = ixgbe_read_sr_word_aci(hw, E610_SR_SW_CHECKSUM_WORD,
2390+
&tmp_checksum);
2391+
ixgbe_release_nvm(hw);
2392+
2393+
if (!err)
2394+
*checksum_val = tmp_checksum;
2395+
}
2396+
2397+
return err;
2398+
}

drivers/net/ethernet/intel/ixgbe/ixgbe_e610.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,5 +59,17 @@ int ixgbe_enter_lplu_e610(struct ixgbe_hw *hw);
5959
int ixgbe_aci_get_netlist_node(struct ixgbe_hw *hw,
6060
struct ixgbe_aci_cmd_get_link_topo *cmd,
6161
u8 *node_part_number, u16 *node_handle);
62+
int ixgbe_acquire_nvm(struct ixgbe_hw *hw,
63+
enum ixgbe_aci_res_access_type access);
64+
void ixgbe_release_nvm(struct ixgbe_hw *hw);
65+
int ixgbe_aci_read_nvm(struct ixgbe_hw *hw, u16 module_typeid, u32 offset,
66+
u16 length, void *data, bool last_command,
67+
bool read_shadow_ram);
68+
int ixgbe_nvm_validate_checksum(struct ixgbe_hw *hw);
69+
int ixgbe_read_sr_word_aci(struct ixgbe_hw *hw, u16 offset, u16 *data);
70+
int ixgbe_read_flat_nvm(struct ixgbe_hw *hw, u32 offset, u32 *length,
71+
u8 *data, bool read_shadow_ram);
72+
int ixgbe_read_ee_aci_e610(struct ixgbe_hw *hw, u16 offset, u16 *data);
73+
int ixgbe_validate_eeprom_checksum_e610(struct ixgbe_hw *hw, u16 *checksum_val);
6274

6375
#endif /* _IXGBE_E610_H_ */

0 commit comments

Comments
 (0)