Skip to content

Commit e882256

Browse files
committed
Merge branch 'sfc-TC-offload-counters'
Edward Cree says: ==================== sfc: TC offload counters EF100 hardware supports attaching counters to action-sets in the MAE. Use these counters to implement stats for TC flower offload. The counters are delivered to the host over a special hardware RX queue which should only ever receive counter update messages, not 'real' network packets. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 7d63b21 + 50f8f2f commit e882256

13 files changed

+998
-9
lines changed

drivers/net/ethernet/sfc/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ sfc-y += efx.o efx_common.o efx_channels.o nic.o \
99
ef100_ethtool.o ef100_rx.o ef100_tx.o
1010
sfc-$(CONFIG_SFC_MTD) += mtd.o
1111
sfc-$(CONFIG_SFC_SRIOV) += sriov.o ef10_sriov.o ef100_sriov.o ef100_rep.o \
12-
mae.o tc.o tc_bindings.o
12+
mae.o tc.o tc_bindings.o tc_counters.o
1313

1414
obj-$(CONFIG_SFC) += sfc.o
1515

drivers/net/ethernet/sfc/ef100_rx.c

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
/* Get the value of a field in the RX prefix */
2222
#define PREFIX_OFFSET_W(_f) (ESF_GZ_RX_PREFIX_ ## _f ## _LBN / 32)
2323
#define PREFIX_OFFSET_B(_f) (ESF_GZ_RX_PREFIX_ ## _f ## _LBN % 32)
24-
#define PREFIX_WIDTH_MASK(_f) ((1UL << ESF_GZ_RX_PREFIX_ ## _f ## _WIDTH) - 1)
24+
#define PREFIX_WIDTH_MASK(_f) ((1ULL << ESF_GZ_RX_PREFIX_ ## _f ## _WIDTH) - 1)
2525
#define PREFIX_WORD(_p, _f) le32_to_cpu((__force __le32)(_p)[PREFIX_OFFSET_W(_f)])
2626
#define PREFIX_FIELD(_p, _f) ((PREFIX_WORD(_p, _f) >> PREFIX_OFFSET_B(_f)) & \
2727
PREFIX_WIDTH_MASK(_f))
@@ -67,6 +67,13 @@ void __ef100_rx_packet(struct efx_channel *channel)
6767

6868
prefix = (u32 *)(eh - ESE_GZ_RX_PKT_PREFIX_LEN);
6969

70+
if (channel->type->receive_raw) {
71+
u32 mark = PREFIX_FIELD(prefix, USER_MARK);
72+
73+
if (channel->type->receive_raw(rx_queue, mark))
74+
return; /* packet was consumed */
75+
}
76+
7077
if (ef100_has_fcs_error(channel, prefix) &&
7178
unlikely(!(efx->net_dev->features & NETIF_F_RXALL)))
7279
goto out;
@@ -183,24 +190,32 @@ void efx_ef100_ev_rx(struct efx_channel *channel, const efx_qword_t *p_event)
183190

184191
void ef100_rx_write(struct efx_rx_queue *rx_queue)
185192
{
193+
unsigned int notified_count = rx_queue->notified_count;
186194
struct efx_rx_buffer *rx_buf;
187195
unsigned int idx;
188196
efx_qword_t *rxd;
189197
efx_dword_t rxdb;
190198

191-
while (rx_queue->notified_count != rx_queue->added_count) {
192-
idx = rx_queue->notified_count & rx_queue->ptr_mask;
199+
while (notified_count != rx_queue->added_count) {
200+
idx = notified_count & rx_queue->ptr_mask;
193201
rx_buf = efx_rx_buffer(rx_queue, idx);
194202
rxd = efx_rx_desc(rx_queue, idx);
195203

196204
EFX_POPULATE_QWORD_1(*rxd, ESF_GZ_RX_BUF_ADDR, rx_buf->dma_addr);
197205

198-
++rx_queue->notified_count;
206+
++notified_count;
199207
}
208+
if (notified_count == rx_queue->notified_count)
209+
return;
200210

201211
wmb();
202212
EFX_POPULATE_DWORD_1(rxdb, ERF_GZ_RX_RING_PIDX,
203213
rx_queue->added_count & rx_queue->ptr_mask);
204214
efx_writed_page(rx_queue->efx, &rxdb,
205215
ER_GZ_RX_RING_DOORBELL, efx_rx_queue_index(rx_queue));
216+
if (rx_queue->grant_credits)
217+
wmb();
218+
rx_queue->notified_count = notified_count;
219+
if (rx_queue->grant_credits)
220+
schedule_work(&rx_queue->grant_work);
206221
}

drivers/net/ethernet/sfc/efx_channels.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1119,6 +1119,8 @@ void efx_start_channels(struct efx_nic *efx)
11191119
struct efx_channel *channel;
11201120

11211121
efx_for_each_channel_rev(channel, efx) {
1122+
if (channel->type->start)
1123+
channel->type->start(channel);
11221124
efx_for_each_channel_tx_queue(tx_queue, channel) {
11231125
efx_init_tx_queue(tx_queue);
11241126
atomic_inc(&efx->active_queues);
@@ -1143,8 +1145,13 @@ void efx_stop_channels(struct efx_nic *efx)
11431145
struct efx_channel *channel;
11441146
int rc = 0;
11451147

1146-
/* Stop RX refill */
1148+
/* Stop special channels and RX refill.
1149+
* The channel's stop has to be called first, since it might wait
1150+
* for a sentinel RX to indicate the channel has fully drained.
1151+
*/
11471152
efx_for_each_channel(channel, efx) {
1153+
if (channel->type->stop)
1154+
channel->type->stop(channel);
11481155
efx_for_each_channel_rx_queue(rx_queue, channel)
11491156
rx_queue->refill_enabled = false;
11501157
}

drivers/net/ethernet/sfc/mae.c

Lines changed: 168 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,117 @@ int efx_mae_lookup_mport(struct efx_nic *efx, u32 selector, u32 *id)
112112
return 0;
113113
}
114114

115+
int efx_mae_start_counters(struct efx_nic *efx, struct efx_rx_queue *rx_queue)
116+
{
117+
MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_COUNTERS_STREAM_START_V2_IN_LEN);
118+
MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_COUNTERS_STREAM_START_OUT_LEN);
119+
u32 out_flags;
120+
size_t outlen;
121+
int rc;
122+
123+
MCDI_SET_WORD(inbuf, MAE_COUNTERS_STREAM_START_V2_IN_QID,
124+
efx_rx_queue_index(rx_queue));
125+
MCDI_SET_WORD(inbuf, MAE_COUNTERS_STREAM_START_V2_IN_PACKET_SIZE,
126+
efx->net_dev->mtu);
127+
MCDI_SET_DWORD(inbuf, MAE_COUNTERS_STREAM_START_V2_IN_COUNTER_TYPES_MASK,
128+
BIT(MAE_COUNTER_TYPE_AR) | BIT(MAE_COUNTER_TYPE_CT) |
129+
BIT(MAE_COUNTER_TYPE_OR));
130+
rc = efx_mcdi_rpc(efx, MC_CMD_MAE_COUNTERS_STREAM_START,
131+
inbuf, sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
132+
if (rc)
133+
return rc;
134+
if (outlen < sizeof(outbuf))
135+
return -EIO;
136+
out_flags = MCDI_DWORD(outbuf, MAE_COUNTERS_STREAM_START_OUT_FLAGS);
137+
if (out_flags & BIT(MC_CMD_MAE_COUNTERS_STREAM_START_OUT_USES_CREDITS_OFST)) {
138+
netif_dbg(efx, drv, efx->net_dev,
139+
"MAE counter stream uses credits\n");
140+
rx_queue->grant_credits = true;
141+
out_flags &= ~BIT(MC_CMD_MAE_COUNTERS_STREAM_START_OUT_USES_CREDITS_OFST);
142+
}
143+
if (out_flags) {
144+
netif_err(efx, drv, efx->net_dev,
145+
"MAE counter stream start: unrecognised flags %x\n",
146+
out_flags);
147+
goto out_stop;
148+
}
149+
return 0;
150+
out_stop:
151+
efx_mae_stop_counters(efx, rx_queue);
152+
return -EOPNOTSUPP;
153+
}
154+
155+
static bool efx_mae_counters_flushed(u32 *flush_gen, u32 *seen_gen)
156+
{
157+
int i;
158+
159+
for (i = 0; i < EFX_TC_COUNTER_TYPE_MAX; i++)
160+
if ((s32)(flush_gen[i] - seen_gen[i]) > 0)
161+
return false;
162+
return true;
163+
}
164+
165+
int efx_mae_stop_counters(struct efx_nic *efx, struct efx_rx_queue *rx_queue)
166+
{
167+
MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_COUNTERS_STREAM_STOP_V2_OUT_LENMAX);
168+
MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_COUNTERS_STREAM_STOP_IN_LEN);
169+
size_t outlen;
170+
int rc, i;
171+
172+
MCDI_SET_WORD(inbuf, MAE_COUNTERS_STREAM_STOP_IN_QID,
173+
efx_rx_queue_index(rx_queue));
174+
rc = efx_mcdi_rpc(efx, MC_CMD_MAE_COUNTERS_STREAM_STOP,
175+
inbuf, sizeof(inbuf), outbuf, sizeof(outbuf), &outlen);
176+
177+
if (rc)
178+
return rc;
179+
180+
netif_dbg(efx, drv, efx->net_dev, "Draining counters:\n");
181+
/* Only process received generation counts */
182+
for (i = 0; (i < (outlen / 4)) && (i < EFX_TC_COUNTER_TYPE_MAX); i++) {
183+
efx->tc->flush_gen[i] = MCDI_ARRAY_DWORD(outbuf,
184+
MAE_COUNTERS_STREAM_STOP_V2_OUT_GENERATION_COUNT,
185+
i);
186+
netif_dbg(efx, drv, efx->net_dev,
187+
"\ttype %u, awaiting gen %u\n", i,
188+
efx->tc->flush_gen[i]);
189+
}
190+
191+
efx->tc->flush_counters = true;
192+
193+
/* Drain can take up to 2 seconds owing to FWRIVERHD-2884; whatever
194+
* timeout we use, that delay is added to unload on nonresponsive
195+
* hardware, so 2500ms seems like a reasonable compromise.
196+
*/
197+
if (!wait_event_timeout(efx->tc->flush_wq,
198+
efx_mae_counters_flushed(efx->tc->flush_gen,
199+
efx->tc->seen_gen),
200+
msecs_to_jiffies(2500)))
201+
netif_warn(efx, drv, efx->net_dev,
202+
"Failed to drain counters RXQ, FW may be unhappy\n");
203+
204+
efx->tc->flush_counters = false;
205+
206+
return rc;
207+
}
208+
209+
void efx_mae_counters_grant_credits(struct work_struct *work)
210+
{
211+
MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_LEN);
212+
struct efx_rx_queue *rx_queue = container_of(work, struct efx_rx_queue,
213+
grant_work);
214+
struct efx_nic *efx = rx_queue->efx;
215+
unsigned int credits;
216+
217+
BUILD_BUG_ON(MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS_OUT_LEN);
218+
credits = READ_ONCE(rx_queue->notified_count) - rx_queue->granted_count;
219+
MCDI_SET_DWORD(inbuf, MAE_COUNTERS_STREAM_GIVE_CREDITS_IN_NUM_CREDITS,
220+
credits);
221+
if (!efx_mcdi_rpc(efx, MC_CMD_MAE_COUNTERS_STREAM_GIVE_CREDITS,
222+
inbuf, sizeof(inbuf), NULL, 0, NULL))
223+
rx_queue->granted_count += credits;
224+
}
225+
115226
static int efx_mae_get_basic_caps(struct efx_nic *efx, struct mae_caps *caps)
116227
{
117228
MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_GET_CAPS_OUT_LEN);
@@ -323,6 +434,57 @@ int efx_mae_match_check_caps(struct efx_nic *efx,
323434
#undef CHECK_BIT
324435
#undef CHECK
325436

437+
int efx_mae_allocate_counter(struct efx_nic *efx, struct efx_tc_counter *cnt)
438+
{
439+
MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_COUNTER_ALLOC_OUT_LEN(1));
440+
MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_COUNTER_ALLOC_V2_IN_LEN);
441+
size_t outlen;
442+
int rc;
443+
444+
if (!cnt)
445+
return -EINVAL;
446+
447+
MCDI_SET_DWORD(inbuf, MAE_COUNTER_ALLOC_V2_IN_REQUESTED_COUNT, 1);
448+
MCDI_SET_DWORD(inbuf, MAE_COUNTER_ALLOC_V2_IN_COUNTER_TYPE, cnt->type);
449+
rc = efx_mcdi_rpc(efx, MC_CMD_MAE_COUNTER_ALLOC, inbuf, sizeof(inbuf),
450+
outbuf, sizeof(outbuf), &outlen);
451+
if (rc)
452+
return rc;
453+
/* pcol says this can't happen, since count is 1 */
454+
if (outlen < sizeof(outbuf))
455+
return -EIO;
456+
cnt->fw_id = MCDI_DWORD(outbuf, MAE_COUNTER_ALLOC_OUT_COUNTER_ID);
457+
cnt->gen = MCDI_DWORD(outbuf, MAE_COUNTER_ALLOC_OUT_GENERATION_COUNT);
458+
return 0;
459+
}
460+
461+
int efx_mae_free_counter(struct efx_nic *efx, struct efx_tc_counter *cnt)
462+
{
463+
MCDI_DECLARE_BUF(outbuf, MC_CMD_MAE_COUNTER_FREE_OUT_LEN(1));
464+
MCDI_DECLARE_BUF(inbuf, MC_CMD_MAE_COUNTER_FREE_V2_IN_LEN);
465+
size_t outlen;
466+
int rc;
467+
468+
MCDI_SET_DWORD(inbuf, MAE_COUNTER_FREE_V2_IN_COUNTER_ID_COUNT, 1);
469+
MCDI_SET_DWORD(inbuf, MAE_COUNTER_FREE_V2_IN_FREE_COUNTER_ID, cnt->fw_id);
470+
MCDI_SET_DWORD(inbuf, MAE_COUNTER_FREE_V2_IN_COUNTER_TYPE, cnt->type);
471+
rc = efx_mcdi_rpc(efx, MC_CMD_MAE_COUNTER_FREE, inbuf, sizeof(inbuf),
472+
outbuf, sizeof(outbuf), &outlen);
473+
if (rc)
474+
return rc;
475+
/* pcol says this can't happen, since count is 1 */
476+
if (outlen < sizeof(outbuf))
477+
return -EIO;
478+
/* FW freed a different ID than we asked for, should also never happen.
479+
* Warn because it means we've now got a different idea to the FW of
480+
* what counters exist, which could cause mayhem later.
481+
*/
482+
if (WARN_ON(MCDI_DWORD(outbuf, MAE_COUNTER_FREE_OUT_FREED_COUNTER_ID) !=
483+
cnt->fw_id))
484+
return -EIO;
485+
return 0;
486+
}
487+
326488
static bool efx_mae_asl_id(u32 id)
327489
{
328490
return !!(id & BIT(31));
@@ -339,8 +501,12 @@ int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act)
339501
MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
340502
MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_DST_MAC_ID,
341503
MC_CMD_MAE_MAC_ADDR_ALLOC_OUT_MAC_ID_NULL);
342-
MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID,
343-
MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_NULL);
504+
if (act->count && !WARN_ON(!act->count->cnt))
505+
MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID,
506+
act->count->cnt->fw_id);
507+
else
508+
MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_ID,
509+
MC_CMD_MAE_COUNTER_ALLOC_OUT_COUNTER_ID_NULL);
344510
MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_COUNTER_LIST_ID,
345511
MC_CMD_MAE_COUNTER_LIST_ALLOC_OUT_COUNTER_LIST_ID_NULL);
346512
MCDI_SET_DWORD(inbuf, MAE_ACTION_SET_ALLOC_IN_ENCAP_HEADER_ID,

drivers/net/ethernet/sfc/mae.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ void efx_mae_mport_mport(struct efx_nic *efx, u32 mport_id, u32 *out);
2727

2828
int efx_mae_lookup_mport(struct efx_nic *efx, u32 selector, u32 *id);
2929

30+
int efx_mae_start_counters(struct efx_nic *efx, struct efx_rx_queue *rx_queue);
31+
int efx_mae_stop_counters(struct efx_nic *efx, struct efx_rx_queue *rx_queue);
32+
void efx_mae_counters_grant_credits(struct work_struct *work);
33+
3034
#define MAE_NUM_FIELDS (MAE_FIELD_ENC_VNET_ID + 1)
3135

3236
struct mae_caps {
@@ -41,6 +45,9 @@ int efx_mae_match_check_caps(struct efx_nic *efx,
4145
const struct efx_tc_match_fields *mask,
4246
struct netlink_ext_ack *extack);
4347

48+
int efx_mae_allocate_counter(struct efx_nic *efx, struct efx_tc_counter *cnt);
49+
int efx_mae_free_counter(struct efx_nic *efx, struct efx_tc_counter *cnt);
50+
4451
int efx_mae_alloc_action_set(struct efx_nic *efx, struct efx_tc_action_set *act);
4552
int efx_mae_free_action_set(struct efx_nic *efx, u32 fw_id);
4653

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
/****************************************************************************
3+
* Driver for Solarflare network controllers and boards
4+
* Copyright 2020 Xilinx, Inc.
5+
*
6+
* This program is free software; you can redistribute it and/or modify it
7+
* under the terms of the GNU General Public License version 2 as published
8+
* by the Free Software Foundation, incorporated herein by reference.
9+
*/
10+
11+
/* Format of counter packets (version 2) from the ef100 Match-Action Engine */
12+
13+
#ifndef EFX_MAE_COUNTER_FORMAT_H
14+
#define EFX_MAE_COUNTER_FORMAT_H
15+
16+
17+
/*------------------------------------------------------------*/
18+
/*
19+
* ER_RX_SL_PACKETISER_HEADER_WORD(160bit):
20+
*
21+
*/
22+
#define ER_RX_SL_PACKETISER_HEADER_WORD_SIZE 20
23+
#define ER_RX_SL_PACKETISER_HEADER_WORD_WIDTH 160
24+
25+
#define ERF_SC_PACKETISER_HEADER_VERSION_LBN 0
26+
#define ERF_SC_PACKETISER_HEADER_VERSION_WIDTH 8
27+
#define ERF_SC_PACKETISER_HEADER_VERSION_VALUE 2
28+
#define ERF_SC_PACKETISER_HEADER_IDENTIFIER_LBN 8
29+
#define ERF_SC_PACKETISER_HEADER_IDENTIFIER_WIDTH 8
30+
#define ERF_SC_PACKETISER_HEADER_IDENTIFIER_AR 0
31+
#define ERF_SC_PACKETISER_HEADER_IDENTIFIER_CT 1
32+
#define ERF_SC_PACKETISER_HEADER_IDENTIFIER_OR 2
33+
#define ERF_SC_PACKETISER_HEADER_HEADER_OFFSET_LBN 16
34+
#define ERF_SC_PACKETISER_HEADER_HEADER_OFFSET_WIDTH 8
35+
#define ERF_SC_PACKETISER_HEADER_HEADER_OFFSET_DEFAULT 0x4
36+
#define ERF_SC_PACKETISER_HEADER_PAYLOAD_OFFSET_LBN 24
37+
#define ERF_SC_PACKETISER_HEADER_PAYLOAD_OFFSET_WIDTH 8
38+
#define ERF_SC_PACKETISER_HEADER_PAYLOAD_OFFSET_DEFAULT 0x14
39+
#define ERF_SC_PACKETISER_HEADER_INDEX_LBN 32
40+
#define ERF_SC_PACKETISER_HEADER_INDEX_WIDTH 16
41+
#define ERF_SC_PACKETISER_HEADER_COUNT_LBN 48
42+
#define ERF_SC_PACKETISER_HEADER_COUNT_WIDTH 16
43+
#define ERF_SC_PACKETISER_HEADER_RESERVED_0_LBN 64
44+
#define ERF_SC_PACKETISER_HEADER_RESERVED_0_WIDTH 32
45+
#define ERF_SC_PACKETISER_HEADER_RESERVED_1_LBN 96
46+
#define ERF_SC_PACKETISER_HEADER_RESERVED_1_WIDTH 32
47+
#define ERF_SC_PACKETISER_HEADER_RESERVED_2_LBN 128
48+
#define ERF_SC_PACKETISER_HEADER_RESERVED_2_WIDTH 32
49+
50+
51+
/*------------------------------------------------------------*/
52+
/*
53+
* ER_RX_SL_PACKETISER_PAYLOAD_WORD(128bit):
54+
*
55+
*/
56+
#define ER_RX_SL_PACKETISER_PAYLOAD_WORD_SIZE 16
57+
#define ER_RX_SL_PACKETISER_PAYLOAD_WORD_WIDTH 128
58+
59+
#define ERF_SC_PACKETISER_PAYLOAD_COUNTER_INDEX_LBN 0
60+
#define ERF_SC_PACKETISER_PAYLOAD_COUNTER_INDEX_WIDTH 24
61+
#define ERF_SC_PACKETISER_PAYLOAD_RESERVED_LBN 24
62+
#define ERF_SC_PACKETISER_PAYLOAD_RESERVED_WIDTH 8
63+
#define ERF_SC_PACKETISER_PAYLOAD_PACKET_COUNT_OFST 4
64+
#define ERF_SC_PACKETISER_PAYLOAD_PACKET_COUNT_SIZE 6
65+
#define ERF_SC_PACKETISER_PAYLOAD_PACKET_COUNT_LBN 32
66+
#define ERF_SC_PACKETISER_PAYLOAD_PACKET_COUNT_WIDTH 48
67+
#define ERF_SC_PACKETISER_PAYLOAD_BYTE_COUNT_OFST 10
68+
#define ERF_SC_PACKETISER_PAYLOAD_BYTE_COUNT_SIZE 6
69+
#define ERF_SC_PACKETISER_PAYLOAD_BYTE_COUNT_LBN 80
70+
#define ERF_SC_PACKETISER_PAYLOAD_BYTE_COUNT_WIDTH 48
71+
72+
73+
#endif /* EFX_MAE_COUNTER_FORMAT_H */

drivers/net/ethernet/sfc/mcdi.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,11 @@ void efx_mcdi_sensor_event(struct efx_nic *efx, efx_qword_t *ev);
221221
#define MCDI_BYTE(_buf, _field) \
222222
((void)BUILD_BUG_ON_ZERO(MC_CMD_ ## _field ## _LEN != 1), \
223223
*MCDI_PTR(_buf, _field))
224+
#define MCDI_SET_WORD(_buf, _field, _value) do { \
225+
BUILD_BUG_ON(MC_CMD_ ## _field ## _LEN != 2); \
226+
BUILD_BUG_ON(MC_CMD_ ## _field ## _OFST & 1); \
227+
*(__force __le16 *)MCDI_PTR(_buf, _field) = cpu_to_le16(_value);\
228+
} while (0)
224229
#define MCDI_WORD(_buf, _field) \
225230
((u16)BUILD_BUG_ON_ZERO(MC_CMD_ ## _field ## _LEN != 2) + \
226231
le16_to_cpu(*(__force const __le16 *)MCDI_PTR(_buf, _field)))

0 commit comments

Comments
 (0)