cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dpaa2-mac.c (15122B)


      1// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
      2/* Copyright 2019 NXP */
      3
      4#include <linux/acpi.h>
      5#include <linux/pcs-lynx.h>
      6#include <linux/phy/phy.h>
      7#include <linux/property.h>
      8
      9#include "dpaa2-eth.h"
     10#include "dpaa2-mac.h"
     11
     12#define phylink_to_dpaa2_mac(config) \
     13	container_of((config), struct dpaa2_mac, phylink_config)
     14
     15#define DPMAC_PROTOCOL_CHANGE_VER_MAJOR		4
     16#define DPMAC_PROTOCOL_CHANGE_VER_MINOR		8
     17
     18#define DPAA2_MAC_FEATURE_PROTOCOL_CHANGE	BIT(0)
     19
     20static int dpaa2_mac_cmp_ver(struct dpaa2_mac *mac,
     21			     u16 ver_major, u16 ver_minor)
     22{
     23	if (mac->ver_major == ver_major)
     24		return mac->ver_minor - ver_minor;
     25	return mac->ver_major - ver_major;
     26}
     27
     28static void dpaa2_mac_detect_features(struct dpaa2_mac *mac)
     29{
     30	mac->features = 0;
     31
     32	if (dpaa2_mac_cmp_ver(mac, DPMAC_PROTOCOL_CHANGE_VER_MAJOR,
     33			      DPMAC_PROTOCOL_CHANGE_VER_MINOR) >= 0)
     34		mac->features |= DPAA2_MAC_FEATURE_PROTOCOL_CHANGE;
     35}
     36
     37static int phy_mode(enum dpmac_eth_if eth_if, phy_interface_t *if_mode)
     38{
     39	*if_mode = PHY_INTERFACE_MODE_NA;
     40
     41	switch (eth_if) {
     42	case DPMAC_ETH_IF_RGMII:
     43		*if_mode = PHY_INTERFACE_MODE_RGMII;
     44		break;
     45	case DPMAC_ETH_IF_USXGMII:
     46		*if_mode = PHY_INTERFACE_MODE_USXGMII;
     47		break;
     48	case DPMAC_ETH_IF_QSGMII:
     49		*if_mode = PHY_INTERFACE_MODE_QSGMII;
     50		break;
     51	case DPMAC_ETH_IF_SGMII:
     52		*if_mode = PHY_INTERFACE_MODE_SGMII;
     53		break;
     54	case DPMAC_ETH_IF_XFI:
     55		*if_mode = PHY_INTERFACE_MODE_10GBASER;
     56		break;
     57	default:
     58		return -EINVAL;
     59	}
     60
     61	return 0;
     62}
     63
     64static enum dpmac_eth_if dpmac_eth_if_mode(phy_interface_t if_mode)
     65{
     66	switch (if_mode) {
     67	case PHY_INTERFACE_MODE_RGMII:
     68	case PHY_INTERFACE_MODE_RGMII_ID:
     69	case PHY_INTERFACE_MODE_RGMII_RXID:
     70	case PHY_INTERFACE_MODE_RGMII_TXID:
     71		return DPMAC_ETH_IF_RGMII;
     72	case PHY_INTERFACE_MODE_USXGMII:
     73		return DPMAC_ETH_IF_USXGMII;
     74	case PHY_INTERFACE_MODE_QSGMII:
     75		return DPMAC_ETH_IF_QSGMII;
     76	case PHY_INTERFACE_MODE_SGMII:
     77		return DPMAC_ETH_IF_SGMII;
     78	case PHY_INTERFACE_MODE_10GBASER:
     79		return DPMAC_ETH_IF_XFI;
     80	case PHY_INTERFACE_MODE_1000BASEX:
     81		return DPMAC_ETH_IF_1000BASEX;
     82	default:
     83		return DPMAC_ETH_IF_MII;
     84	}
     85}
     86
     87static struct fwnode_handle *dpaa2_mac_get_node(struct device *dev,
     88						u16 dpmac_id)
     89{
     90	struct fwnode_handle *fwnode, *parent = NULL, *child  = NULL;
     91	struct device_node *dpmacs = NULL;
     92	int err;
     93	u32 id;
     94
     95	fwnode = dev_fwnode(dev->parent);
     96	if (is_of_node(fwnode)) {
     97		dpmacs = of_find_node_by_name(NULL, "dpmacs");
     98		if (!dpmacs)
     99			return NULL;
    100		parent = of_fwnode_handle(dpmacs);
    101	} else if (is_acpi_node(fwnode)) {
    102		parent = fwnode;
    103	} else {
    104		/* The root dprc device didn't yet get to finalize it's probe,
    105		 * thus the fwnode field is not yet set. Defer probe if we are
    106		 * facing this situation.
    107		 */
    108		return ERR_PTR(-EPROBE_DEFER);
    109	}
    110
    111	fwnode_for_each_child_node(parent, child) {
    112		err = -EINVAL;
    113		if (is_acpi_device_node(child))
    114			err = acpi_get_local_address(ACPI_HANDLE_FWNODE(child), &id);
    115		else if (is_of_node(child))
    116			err = of_property_read_u32(to_of_node(child), "reg", &id);
    117		if (err)
    118			continue;
    119
    120		if (id == dpmac_id) {
    121			of_node_put(dpmacs);
    122			return child;
    123		}
    124	}
    125	of_node_put(dpmacs);
    126	return NULL;
    127}
    128
    129static int dpaa2_mac_get_if_mode(struct fwnode_handle *dpmac_node,
    130				 struct dpmac_attr attr)
    131{
    132	phy_interface_t if_mode;
    133	int err;
    134
    135	err = fwnode_get_phy_mode(dpmac_node);
    136	if (err > 0)
    137		return err;
    138
    139	err = phy_mode(attr.eth_if, &if_mode);
    140	if (!err)
    141		return if_mode;
    142
    143	return err;
    144}
    145
    146static struct phylink_pcs *dpaa2_mac_select_pcs(struct phylink_config *config,
    147						phy_interface_t interface)
    148{
    149	struct dpaa2_mac *mac = phylink_to_dpaa2_mac(config);
    150
    151	return mac->pcs;
    152}
    153
    154static void dpaa2_mac_config(struct phylink_config *config, unsigned int mode,
    155			     const struct phylink_link_state *state)
    156{
    157	struct dpaa2_mac *mac = phylink_to_dpaa2_mac(config);
    158	struct dpmac_link_state *dpmac_state = &mac->state;
    159	int err;
    160
    161	if (state->an_enabled)
    162		dpmac_state->options |= DPMAC_LINK_OPT_AUTONEG;
    163	else
    164		dpmac_state->options &= ~DPMAC_LINK_OPT_AUTONEG;
    165
    166	err = dpmac_set_link_state(mac->mc_io, 0,
    167				   mac->mc_dev->mc_handle, dpmac_state);
    168	if (err)
    169		netdev_err(mac->net_dev, "%s: dpmac_set_link_state() = %d\n",
    170			   __func__, err);
    171
    172	if (!mac->serdes_phy)
    173		return;
    174
    175	/* This happens only if we support changing of protocol at runtime */
    176	err = dpmac_set_protocol(mac->mc_io, 0, mac->mc_dev->mc_handle,
    177				 dpmac_eth_if_mode(state->interface));
    178	if (err)
    179		netdev_err(mac->net_dev,  "dpmac_set_protocol() = %d\n", err);
    180
    181	err = phy_set_mode_ext(mac->serdes_phy, PHY_MODE_ETHERNET, state->interface);
    182	if (err)
    183		netdev_err(mac->net_dev, "phy_set_mode_ext() = %d\n", err);
    184}
    185
    186static void dpaa2_mac_link_up(struct phylink_config *config,
    187			      struct phy_device *phy,
    188			      unsigned int mode, phy_interface_t interface,
    189			      int speed, int duplex,
    190			      bool tx_pause, bool rx_pause)
    191{
    192	struct dpaa2_mac *mac = phylink_to_dpaa2_mac(config);
    193	struct dpmac_link_state *dpmac_state = &mac->state;
    194	int err;
    195
    196	dpmac_state->up = 1;
    197
    198	dpmac_state->rate = speed;
    199
    200	if (duplex == DUPLEX_HALF)
    201		dpmac_state->options |= DPMAC_LINK_OPT_HALF_DUPLEX;
    202	else if (duplex == DUPLEX_FULL)
    203		dpmac_state->options &= ~DPMAC_LINK_OPT_HALF_DUPLEX;
    204
    205	if (rx_pause)
    206		dpmac_state->options |= DPMAC_LINK_OPT_PAUSE;
    207	else
    208		dpmac_state->options &= ~DPMAC_LINK_OPT_PAUSE;
    209
    210	if (rx_pause ^ tx_pause)
    211		dpmac_state->options |= DPMAC_LINK_OPT_ASYM_PAUSE;
    212	else
    213		dpmac_state->options &= ~DPMAC_LINK_OPT_ASYM_PAUSE;
    214
    215	err = dpmac_set_link_state(mac->mc_io, 0,
    216				   mac->mc_dev->mc_handle, dpmac_state);
    217	if (err)
    218		netdev_err(mac->net_dev, "%s: dpmac_set_link_state() = %d\n",
    219			   __func__, err);
    220}
    221
    222static void dpaa2_mac_link_down(struct phylink_config *config,
    223				unsigned int mode,
    224				phy_interface_t interface)
    225{
    226	struct dpaa2_mac *mac = phylink_to_dpaa2_mac(config);
    227	struct dpmac_link_state *dpmac_state = &mac->state;
    228	int err;
    229
    230	dpmac_state->up = 0;
    231	err = dpmac_set_link_state(mac->mc_io, 0,
    232				   mac->mc_dev->mc_handle, dpmac_state);
    233	if (err)
    234		netdev_err(mac->net_dev, "dpmac_set_link_state() = %d\n", err);
    235}
    236
    237static const struct phylink_mac_ops dpaa2_mac_phylink_ops = {
    238	.validate = phylink_generic_validate,
    239	.mac_select_pcs = dpaa2_mac_select_pcs,
    240	.mac_config = dpaa2_mac_config,
    241	.mac_link_up = dpaa2_mac_link_up,
    242	.mac_link_down = dpaa2_mac_link_down,
    243};
    244
    245static int dpaa2_pcs_create(struct dpaa2_mac *mac,
    246			    struct fwnode_handle *dpmac_node,
    247			    int id)
    248{
    249	struct mdio_device *mdiodev;
    250	struct fwnode_handle *node;
    251
    252	node = fwnode_find_reference(dpmac_node, "pcs-handle", 0);
    253	if (IS_ERR(node)) {
    254		/* do not error out on old DTS files */
    255		netdev_warn(mac->net_dev, "pcs-handle node not found\n");
    256		return 0;
    257	}
    258
    259	if (!fwnode_device_is_available(node)) {
    260		netdev_err(mac->net_dev, "pcs-handle node not available\n");
    261		fwnode_handle_put(node);
    262		return -ENODEV;
    263	}
    264
    265	mdiodev = fwnode_mdio_find_device(node);
    266	fwnode_handle_put(node);
    267	if (!mdiodev)
    268		return -EPROBE_DEFER;
    269
    270	mac->pcs = lynx_pcs_create(mdiodev);
    271	if (!mac->pcs) {
    272		netdev_err(mac->net_dev, "lynx_pcs_create() failed\n");
    273		put_device(&mdiodev->dev);
    274		return -ENOMEM;
    275	}
    276
    277	return 0;
    278}
    279
    280static void dpaa2_pcs_destroy(struct dpaa2_mac *mac)
    281{
    282	struct phylink_pcs *phylink_pcs = mac->pcs;
    283
    284	if (phylink_pcs) {
    285		struct mdio_device *mdio = lynx_get_mdio_device(phylink_pcs);
    286		struct device *dev = &mdio->dev;
    287
    288		lynx_pcs_destroy(phylink_pcs);
    289		put_device(dev);
    290		mac->pcs = NULL;
    291	}
    292}
    293
    294static void dpaa2_mac_set_supported_interfaces(struct dpaa2_mac *mac)
    295{
    296	int intf, err;
    297
    298	/* We support the current interface mode, and if we have a PCS
    299	 * similar interface modes that do not require the SerDes lane to be
    300	 * reconfigured.
    301	 */
    302	__set_bit(mac->if_mode, mac->phylink_config.supported_interfaces);
    303	if (mac->pcs) {
    304		switch (mac->if_mode) {
    305		case PHY_INTERFACE_MODE_1000BASEX:
    306		case PHY_INTERFACE_MODE_SGMII:
    307			__set_bit(PHY_INTERFACE_MODE_1000BASEX,
    308				  mac->phylink_config.supported_interfaces);
    309			__set_bit(PHY_INTERFACE_MODE_SGMII,
    310				  mac->phylink_config.supported_interfaces);
    311			break;
    312
    313		default:
    314			break;
    315		}
    316	}
    317
    318	if (!mac->serdes_phy)
    319		return;
    320
    321	/* In case we have access to the SerDes phy/lane, then ask the SerDes
    322	 * driver what interfaces are supported based on the current PLL
    323	 * configuration.
    324	 */
    325	for (intf = 0; intf < PHY_INTERFACE_MODE_MAX; intf++) {
    326		if (intf == PHY_INTERFACE_MODE_NA)
    327			continue;
    328
    329		err = phy_validate(mac->serdes_phy, PHY_MODE_ETHERNET, intf, NULL);
    330		if (err)
    331			continue;
    332
    333		__set_bit(intf, mac->phylink_config.supported_interfaces);
    334	}
    335}
    336
    337void dpaa2_mac_start(struct dpaa2_mac *mac)
    338{
    339	if (mac->serdes_phy)
    340		phy_power_on(mac->serdes_phy);
    341}
    342
    343void dpaa2_mac_stop(struct dpaa2_mac *mac)
    344{
    345	if (mac->serdes_phy)
    346		phy_power_off(mac->serdes_phy);
    347}
    348
    349int dpaa2_mac_connect(struct dpaa2_mac *mac)
    350{
    351	struct net_device *net_dev = mac->net_dev;
    352	struct fwnode_handle *dpmac_node;
    353	struct phy *serdes_phy = NULL;
    354	struct phylink *phylink;
    355	int err;
    356
    357	mac->if_link_type = mac->attr.link_type;
    358
    359	dpmac_node = mac->fw_node;
    360	if (!dpmac_node) {
    361		netdev_err(net_dev, "No dpmac@%d node found.\n", mac->attr.id);
    362		return -ENODEV;
    363	}
    364
    365	err = dpaa2_mac_get_if_mode(dpmac_node, mac->attr);
    366	if (err < 0)
    367		return -EINVAL;
    368	mac->if_mode = err;
    369
    370	if (mac->features & DPAA2_MAC_FEATURE_PROTOCOL_CHANGE &&
    371	    !phy_interface_mode_is_rgmii(mac->if_mode) &&
    372	    is_of_node(dpmac_node)) {
    373		serdes_phy = of_phy_get(to_of_node(dpmac_node), NULL);
    374
    375		if (serdes_phy == ERR_PTR(-ENODEV))
    376			serdes_phy = NULL;
    377		else if (IS_ERR(serdes_phy))
    378			return PTR_ERR(serdes_phy);
    379		else
    380			phy_init(serdes_phy);
    381	}
    382	mac->serdes_phy = serdes_phy;
    383
    384	/* The MAC does not have the capability to add RGMII delays so
    385	 * error out if the interface mode requests them and there is no PHY
    386	 * to act upon them
    387	 */
    388	if (of_phy_is_fixed_link(to_of_node(dpmac_node)) &&
    389	    (mac->if_mode == PHY_INTERFACE_MODE_RGMII_ID ||
    390	     mac->if_mode == PHY_INTERFACE_MODE_RGMII_RXID ||
    391	     mac->if_mode == PHY_INTERFACE_MODE_RGMII_TXID)) {
    392		netdev_err(net_dev, "RGMII delay not supported\n");
    393		return -EINVAL;
    394	}
    395
    396	if ((mac->attr.link_type == DPMAC_LINK_TYPE_PHY &&
    397	     mac->attr.eth_if != DPMAC_ETH_IF_RGMII) ||
    398	    mac->attr.link_type == DPMAC_LINK_TYPE_BACKPLANE) {
    399		err = dpaa2_pcs_create(mac, dpmac_node, mac->attr.id);
    400		if (err)
    401			return err;
    402	}
    403
    404	memset(&mac->phylink_config, 0, sizeof(mac->phylink_config));
    405	mac->phylink_config.dev = &net_dev->dev;
    406	mac->phylink_config.type = PHYLINK_NETDEV;
    407
    408	mac->phylink_config.mac_capabilities = MAC_SYM_PAUSE | MAC_ASYM_PAUSE |
    409		MAC_10FD | MAC_100FD | MAC_1000FD | MAC_2500FD | MAC_5000FD |
    410		MAC_10000FD;
    411
    412	dpaa2_mac_set_supported_interfaces(mac);
    413
    414	phylink = phylink_create(&mac->phylink_config,
    415				 dpmac_node, mac->if_mode,
    416				 &dpaa2_mac_phylink_ops);
    417	if (IS_ERR(phylink)) {
    418		err = PTR_ERR(phylink);
    419		goto err_pcs_destroy;
    420	}
    421	mac->phylink = phylink;
    422
    423	err = phylink_fwnode_phy_connect(mac->phylink, dpmac_node, 0);
    424	if (err) {
    425		netdev_err(net_dev, "phylink_fwnode_phy_connect() = %d\n", err);
    426		goto err_phylink_destroy;
    427	}
    428
    429	return 0;
    430
    431err_phylink_destroy:
    432	phylink_destroy(mac->phylink);
    433err_pcs_destroy:
    434	dpaa2_pcs_destroy(mac);
    435
    436	return err;
    437}
    438
    439void dpaa2_mac_disconnect(struct dpaa2_mac *mac)
    440{
    441	if (!mac->phylink)
    442		return;
    443
    444	phylink_disconnect_phy(mac->phylink);
    445	phylink_destroy(mac->phylink);
    446	dpaa2_pcs_destroy(mac);
    447	of_phy_put(mac->serdes_phy);
    448	mac->serdes_phy = NULL;
    449}
    450
    451int dpaa2_mac_open(struct dpaa2_mac *mac)
    452{
    453	struct fsl_mc_device *dpmac_dev = mac->mc_dev;
    454	struct net_device *net_dev = mac->net_dev;
    455	struct fwnode_handle *fw_node;
    456	int err;
    457
    458	err = dpmac_open(mac->mc_io, 0, dpmac_dev->obj_desc.id,
    459			 &dpmac_dev->mc_handle);
    460	if (err || !dpmac_dev->mc_handle) {
    461		netdev_err(net_dev, "dpmac_open() = %d\n", err);
    462		return -ENODEV;
    463	}
    464
    465	err = dpmac_get_attributes(mac->mc_io, 0, dpmac_dev->mc_handle,
    466				   &mac->attr);
    467	if (err) {
    468		netdev_err(net_dev, "dpmac_get_attributes() = %d\n", err);
    469		goto err_close_dpmac;
    470	}
    471
    472	err = dpmac_get_api_version(mac->mc_io, 0, &mac->ver_major, &mac->ver_minor);
    473	if (err) {
    474		netdev_err(net_dev, "dpmac_get_api_version() = %d\n", err);
    475		goto err_close_dpmac;
    476	}
    477
    478	dpaa2_mac_detect_features(mac);
    479
    480	/* Find the device node representing the MAC device and link the device
    481	 * behind the associated netdev to it.
    482	 */
    483	fw_node = dpaa2_mac_get_node(&mac->mc_dev->dev, mac->attr.id);
    484	if (IS_ERR(fw_node)) {
    485		err = PTR_ERR(fw_node);
    486		goto err_close_dpmac;
    487	}
    488
    489	mac->fw_node = fw_node;
    490	net_dev->dev.of_node = to_of_node(mac->fw_node);
    491
    492	return 0;
    493
    494err_close_dpmac:
    495	dpmac_close(mac->mc_io, 0, dpmac_dev->mc_handle);
    496	return err;
    497}
    498
    499void dpaa2_mac_close(struct dpaa2_mac *mac)
    500{
    501	struct fsl_mc_device *dpmac_dev = mac->mc_dev;
    502
    503	dpmac_close(mac->mc_io, 0, dpmac_dev->mc_handle);
    504	if (mac->fw_node)
    505		fwnode_handle_put(mac->fw_node);
    506}
    507
    508static char dpaa2_mac_ethtool_stats[][ETH_GSTRING_LEN] = {
    509	[DPMAC_CNT_ING_ALL_FRAME]		= "[mac] rx all frames",
    510	[DPMAC_CNT_ING_GOOD_FRAME]		= "[mac] rx frames ok",
    511	[DPMAC_CNT_ING_ERR_FRAME]		= "[mac] rx frame errors",
    512	[DPMAC_CNT_ING_FRAME_DISCARD]		= "[mac] rx frame discards",
    513	[DPMAC_CNT_ING_UCAST_FRAME]		= "[mac] rx u-cast",
    514	[DPMAC_CNT_ING_BCAST_FRAME]		= "[mac] rx b-cast",
    515	[DPMAC_CNT_ING_MCAST_FRAME]		= "[mac] rx m-cast",
    516	[DPMAC_CNT_ING_FRAME_64]		= "[mac] rx 64 bytes",
    517	[DPMAC_CNT_ING_FRAME_127]		= "[mac] rx 65-127 bytes",
    518	[DPMAC_CNT_ING_FRAME_255]		= "[mac] rx 128-255 bytes",
    519	[DPMAC_CNT_ING_FRAME_511]		= "[mac] rx 256-511 bytes",
    520	[DPMAC_CNT_ING_FRAME_1023]		= "[mac] rx 512-1023 bytes",
    521	[DPMAC_CNT_ING_FRAME_1518]		= "[mac] rx 1024-1518 bytes",
    522	[DPMAC_CNT_ING_FRAME_1519_MAX]		= "[mac] rx 1519-max bytes",
    523	[DPMAC_CNT_ING_FRAG]			= "[mac] rx frags",
    524	[DPMAC_CNT_ING_JABBER]			= "[mac] rx jabber",
    525	[DPMAC_CNT_ING_ALIGN_ERR]		= "[mac] rx align errors",
    526	[DPMAC_CNT_ING_OVERSIZED]		= "[mac] rx oversized",
    527	[DPMAC_CNT_ING_VALID_PAUSE_FRAME]	= "[mac] rx pause",
    528	[DPMAC_CNT_ING_BYTE]			= "[mac] rx bytes",
    529	[DPMAC_CNT_EGR_GOOD_FRAME]		= "[mac] tx frames ok",
    530	[DPMAC_CNT_EGR_UCAST_FRAME]		= "[mac] tx u-cast",
    531	[DPMAC_CNT_EGR_MCAST_FRAME]		= "[mac] tx m-cast",
    532	[DPMAC_CNT_EGR_BCAST_FRAME]		= "[mac] tx b-cast",
    533	[DPMAC_CNT_EGR_ERR_FRAME]		= "[mac] tx frame errors",
    534	[DPMAC_CNT_EGR_UNDERSIZED]		= "[mac] tx undersized",
    535	[DPMAC_CNT_EGR_VALID_PAUSE_FRAME]	= "[mac] tx b-pause",
    536	[DPMAC_CNT_EGR_BYTE]			= "[mac] tx bytes",
    537};
    538
    539#define DPAA2_MAC_NUM_STATS	ARRAY_SIZE(dpaa2_mac_ethtool_stats)
    540
    541int dpaa2_mac_get_sset_count(void)
    542{
    543	return DPAA2_MAC_NUM_STATS;
    544}
    545
    546void dpaa2_mac_get_strings(u8 *data)
    547{
    548	u8 *p = data;
    549	int i;
    550
    551	for (i = 0; i < DPAA2_MAC_NUM_STATS; i++) {
    552		strlcpy(p, dpaa2_mac_ethtool_stats[i], ETH_GSTRING_LEN);
    553		p += ETH_GSTRING_LEN;
    554	}
    555}
    556
    557void dpaa2_mac_get_ethtool_stats(struct dpaa2_mac *mac, u64 *data)
    558{
    559	struct fsl_mc_device *dpmac_dev = mac->mc_dev;
    560	int i, err;
    561	u64 value;
    562
    563	for (i = 0; i < DPAA2_MAC_NUM_STATS; i++) {
    564		err = dpmac_get_counter(mac->mc_io, 0, dpmac_dev->mc_handle,
    565					i, &value);
    566		if (err) {
    567			netdev_err_once(mac->net_dev,
    568					"dpmac_get_counter error %d\n", err);
    569			*(data + i) = U64_MAX;
    570			continue;
    571		}
    572		*(data + i) = value;
    573	}
    574}