vmxnet3 device driver
[vpp.git] / src / plugins / vmxnet3 / vmxnet3.h
1 /*
2  * Copyright (c) 2018 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #ifndef __included_vmnet_vmnet_h__
17 #define __included_vmnet_vmnet_h__
18
19 #define foreach_vmxnet3_tx_func_error          \
20   _(ERROR_PACKETS, "error packets") \
21   _(NO_FREE_SLOTS, "no free tx slots")
22
23 typedef enum
24 {
25 #define _(f,s) VMXNET3_TX_ERROR_##f,
26   foreach_vmxnet3_tx_func_error
27 #undef _
28     VMXNET3_TX_N_ERROR,
29 } vmxnet3_tx_func_error_t;
30
31 #define foreach_vmxnet3_rxmode_flags \
32   _(0, UCAST, "unicast") \
33   _(1, MCAST, "multicast")                 \
34   _(2, BCAST, "broadcast") \
35   _(3, ALL_MULTI, "all multicast") \
36   _(4, PROMISC, "promiscuous")
37
38 enum
39 {
40 #define _(a, b, c) VMXNET3_RXMODE_##b = (1 << a),
41   foreach_vmxnet3_rxmode_flags
42 #undef _
43 };
44
45 /* BAR 0 */
46 #define VMXNET3_REG_IMR     0x0000      /* Interrupt Mask Register */
47 #define VMXNET3_REG_TXPROD  0x0600      /* Tx Producer Index */
48 #define VMXNET3_REG_RXPROD  0x0800      /* Rx Producer Index for ring 1 */
49 #define VMXNET3_REG_RXPROD2 0x0A00      /* Rx Producer Index for ring 2 */
50
51
52 /* BAR 1 */
53 #define VMXNET3_REG_VRRS 0x0000 /* VMXNET3 Revision Report Selection */
54 #define VMXNET3_REG_UVRS 0x0008 /* UPT Version Report Selection */
55 #define VMXNET3_REG_DSAL 0x0010 /* Driver Shared Address Low */
56 #define VMXNET3_REG_DSAH 0x0018 /* Driver Shared Address High */
57 #define VMXNET3_REG_CMD  0x0020 /* Command */
58 #define VMXNET3_REG_MACL 0x0028 /* MAC Address Low */
59 #define VMXNET3_REG_MACH 0x0030 /* MAC Address High */
60 #define VMXNET3_REG_ICR  0x0038 /* Interrupt Cause Register */
61 #define VMXNET3_REG_ECR  0x0040 /* Event Cause Register */
62
63 #define VMXNET3_VLAN_LEN 4
64 #define VMXNET3_FCS_LEN  4
65 #define VMXNET3_MTU (1514 + VMXNET3_VLAN_LEN + VMXNET3_FCS_LEN)
66
67 #define VMXNET3_RXF_BTYPE (1 << 14)     /* rx body buffer type */
68 #define VMXNET3_RXF_GEN   (1 << 31)     /* rx generation */
69 #define VMXNET3_RXCF_GEN  (1 << 31)     /* rx completion generation */
70 #define VMXNET3_RXC_INDEX (0xFFF)       /* rx completion index mask */
71
72 #define VMXNET3_TXF_GEN  (1 << 14)      /* tx generation */
73 #define VMXNET3_TXF_EOP  (1 << 12)      /* tx end of packet */
74 #define VMXNET3_TXF_CQ   (1 << 13)      /* tx completion request */
75 #define VMXNET3_TXCF_GEN (1 << 31)      /* tx completion generation */
76 #define VMXNET3_TXC_INDEX (0xFFF)       /* tx completion index mask */
77
78 #define VMXNET3_RX_RING_SIZE 2
79 #define VMXNET3_INPUT_REFILL_THRESHOLD 32
80 #define VMXNET3_NUM_TX_DESC 1024
81 #define VMXNET3_NUM_TX_COMP VMXNET3_NUM_TX_DESC
82 #define VMXNET3_NUM_RX_DESC 1024
83 #define VMXNET3_NUM_RX_COMP VMXNET3_NUM_RX_DESC
84
85 #define VMXNET3_VERSION_MAGIC 0x69505845
86 #define VMXNET3_SHARED_MAGIC  0xbabefee1
87 #define VMXNET3_VERSION_SELECT     1
88 #define VMXNET3_UPT_VERSION_SELECT 1
89 #define VMXNET3_MAX_INTRS          25
90 #define VMXNET3_IC_DISABLE_ALL     0x1
91
92 #define VMXNET3_GOS_BITS_32     (1 << 0)
93 #define VMXNET3_GOS_BITS_64     (2 << 0)
94 #define VMXNET3_GOS_TYPE_LINUX  (1 << 2)
95 #define VMXNET3_RXCL_LEN_MASK   (0x3FFF)        // 14 bits
96 #define VMXNET3_RXCL_ERROR      (1 << 14)
97 #define VMXNET3_RXCI_EOP        (1 << 14)
98 #define VMXNET3_RXCI_SOP        (1 << 15)
99
100 #define foreach_vmxnet3_device_flags \
101   _(0, INITIALIZED, "initialized") \
102   _(1, ERROR, "error")             \
103   _(2, ADMIN_UP, "admin-up") \
104   _(3, IOVA, "iova") \
105   _(4, LINK_UP, "link-up") \
106   _(5, SHARED_TXQ_LOCK, "shared-txq-lock") \
107   _(6, ELOG, "elog")
108
109 enum
110 {
111 #define _(a, b, c) VMXNET3_DEVICE_F_##b = (1 << a),
112   foreach_vmxnet3_device_flags
113 #undef _
114 };
115
116 #define foreach_vmxnet3_set_cmds \
117   _(0, ACTIVATE_DEV, "activate device") \
118   _(1, QUIESCE_DEV, "quiesce device") \
119   _(2, RESET_DEV, "reset device") \
120   _(3, UPDATE_RX_MODE, "update rx mode") \
121   _(4, UPDATE_MAC_FILTERS, "update mac filters") \
122   _(5, UPDATE_VLAN_FILTERS, "update vlan filters") \
123   _(6, UPDATE_RSSIDT, "update rss idt") \
124   _(7, UPDATE_IML, "update iml") \
125   _(8, UPDATE_PMCFG, "update pm cfg") \
126   _(9, UPDATE_FEATURE, "update feature") \
127   _(10, STOP_EMULATION, "stop emulation") \
128   _(11, LOAD_PLUGIN, "load plugin") \
129   _(12, ACTIVATE_VF, "activate vf") \
130   _(13, RESERVED3, "reserved 3") \
131   _(14, RESERVED4, "reservced 4") \
132   _(15, REGISTER_MEMREGS, "register mem regs")
133
134 enum
135 {
136 #define _(a, b, c) VMXNET3_CMD_##b = (a + 0xCAFE0000),
137   foreach_vmxnet3_set_cmds
138 #undef _
139 };
140
141 #define foreach_vmxnet3_get_cmds \
142   _(0, GET_QUEUE_STATUS, "get queue status") \
143   _(1, GET_STATS, "get stats") \
144   _(2, GET_LINK, "get link") \
145   _(3, GET_PERM_MAC_LO, "get perm mac lo") \
146   _(4, GET_PERM_MAC_HI, "get perm mac hi") \
147   _(5, GET_DID_LO, "get did lo") \
148   _(6, GET_DID_HI, "get did hi") \
149   _(7, GET_DEV_EXTRA_INFO, "get dev extra info") \
150   _(8, GET_CONF_INTR, "get conf intr") \
151   _(9, GET_ADAPTIVE_RING_INFO, "get adaptive ring info") \
152   _(10, GET_TXDATA_DESC_SIZE, "gte txdata desc size") \
153   _(11, RESERVED5, "reserved5")
154
155 enum
156 {
157 #define _(a, b, c) VMXNET3_CMD_##b = (a + 0xF00D0000),
158   foreach_vmxnet3_get_cmds
159 #undef _
160 };
161
162 typedef CLIB_PACKED (struct
163                      {
164                      u32 version; u32 guest_info; u32 version_support;
165                      u32 upt_version_support; u64 upt_features;
166                      u64 driver_data_address; u64 queue_desc_address;
167                      u32 driver_data_len; u32 queue_desc_len;
168                      u32 mtu;
169                      u16 max_num_rx_sg; u8 num_tx_queues; u8 num_rx_queues;
170                      u32 pad[4];
171                      }) vmxnet3_misc_config;
172
173 typedef CLIB_PACKED (struct
174                      {
175                      u8 mask_mode;
176                      u8 num_intrs;
177                      u8 event_intr_index;
178                      u8 moderation_level[VMXNET3_MAX_INTRS]; u32 control;
179                      u32 pad[2];
180                      }) vmxnet3_interrupt_config;
181
182 typedef CLIB_PACKED (struct
183                      {
184                      u32 mode;
185                      u16 multicast_len;
186                      u16 pad; u64 multicast_address; u8 vlan_filter[512];
187                      }) vmxnet3_rx_filter_config;
188
189 typedef CLIB_PACKED (struct
190                      {
191                      u32 version; u32 length;
192                      u64 address;
193                      }) vmxnet3_variable_config;
194
195 typedef CLIB_PACKED (struct
196                      {
197                      u32 magic;
198                      u32 pad;
199                      vmxnet3_misc_config misc;
200                      vmxnet3_interrupt_config interrupt;
201                      vmxnet3_rx_filter_config rx_filter;
202                      vmxnet3_variable_config rss;
203                      vmxnet3_variable_config pattern;
204                      vmxnet3_variable_config plugin; u32 ecr;
205                      u32 pad1[5];
206                      }) vmxnet3_shared;
207
208 typedef CLIB_PACKED (struct
209                      {
210                      u8 stopped;
211                      u8 pad[3];
212                      u32 error;
213                      }) vmxnet3_queue_status;
214
215 typedef CLIB_PACKED (struct
216                      {
217                      u32 num_deferred; u32 threshold;
218                      u64 pad;
219                      }) vmxnet3_tx_queue_control;
220
221 typedef CLIB_PACKED (struct
222                      {
223                      u64 desc_address;
224                      u64 data_address;
225                      u64 comp_address; u64 driver_data_address; u64 pad;
226                      u32 num_desc;
227                      u32 num_data;
228                      u32 num_comp; u32 driver_data_len; u8 intr_index;
229                      u8 pad1[7];
230                      }) vmxnet3_tx_queue_config;
231
232 typedef CLIB_PACKED (struct
233                      {
234                      u64 tso_pkts;
235                      u64 tso_bytes;
236                      u64 ucast_pkts; u64 ucast_bytes; u64 mcast_pkts;
237                      u64 mcast_bytes;
238                      u64 bcast_pkts; u64 bcast_bytes; u64 error_pkts;
239                      u64 discard_pkts;
240                      }) vmxnet3_tx_stats;
241
242 typedef CLIB_PACKED (struct
243                      {
244                      vmxnet3_tx_queue_control ctrl;
245                      vmxnet3_tx_queue_config cfg;
246                      vmxnet3_queue_status status; vmxnet3_tx_stats stats;
247                      u8 pad[88];
248                      }) vmxnet3_tx_queue;
249
250 typedef CLIB_PACKED (struct
251                      {
252                      u8 update_prod; u8 pad[7];
253                      u64 pad1;
254                      }) vmxnet3_rx_queue_control;
255
256 typedef CLIB_PACKED (struct
257                      {
258                      u64 desc_address[2];
259                      u64 comp_address; u64 driver_data_address; u64 pad;
260                      u32 num_desc[2];
261                      u32 num_comp; u32 driver_data_len; u8 intr_index;
262                      u8 pad1[7];
263                      }) vmxnet3_rx_queue_config;
264
265 typedef CLIB_PACKED (struct
266                      {
267                      u64 lro_pkts;
268                      u64 lro_bytes;
269                      u64 ucast_pkts; u64 ucast_bytes; u64 mcast_pkts;
270                      u64 mcast_bytes;
271                      u64 bcast_pkts; u64 bcast_bytes; u64 nobuf_pkts;
272                      u64 error_pkts;
273                      }) vmxnet3_rx_stats;
274
275 typedef CLIB_PACKED (struct
276                      {
277                      vmxnet3_rx_queue_control ctrl;
278                      vmxnet3_rx_queue_config cfg;
279                      vmxnet3_queue_status status; vmxnet3_rx_stats stats;
280                      u8 pad[88];
281                      }) vmxnet3_rx_queue;
282
283 typedef CLIB_PACKED (struct
284                      {
285                      vmxnet3_tx_queue tx; vmxnet3_rx_queue rx;
286                      }) vmxnet3_queues;
287
288 /*
289  * flags:
290  *   buffer length   -- bits 0-13
291  *   buffer type     -- bit  14
292  *   descriptor type -- bit  15
293  *   reserved        -- bits 16-30
294  *   generation      -- bit  31
295  */
296 typedef CLIB_PACKED (struct
297                      {
298                      u64 address;
299                      u32 flags;
300                      u32 pad;
301                      }) vmxnet3_rx_desc;
302
303 /*
304  * index:
305  *   RX desc index           -- bits 0-11
306  *   ext1                    -- bits 12-13
307  *   end of packet           -- bit  14
308  *   start of packet         -- bit  15
309  *   ring ID                 -- bits 16-25
310  *   RSS hash type           -- bits 26-29
311  *   checksum not calculated -- bit  30
312  *   ext2                    -- bit  31
313  *
314  * rss: RSS hash value
315  *
316  * len:
317  *   data length             -- bits 0-13
318  *   error                   -- bit  14
319  *   tag is stripped         -- bit  15
320  *   tag stripped            -- bits 16-31
321  *
322  * flags:
323  *   checksum                -- bits 0 - 15
324  *   tcp/udp checksum correct-- bit  16
325  *   udp packet              -- bit  17
326  *   tcp packet              -- bit  18
327  *   ip checksum correct     -- bit  19
328  *   ipv6                    -- bit  20
329  *   ipv4                    -- bit  21
330  *   ip fragment             -- bit  22
331  *   frame crc correct       -- bit  23
332  *   completion type         -- bits 24-30
333  *   generation              -- bit  31
334  */
335 typedef CLIB_PACKED (struct
336                      {
337                      u32 index; u32 rss;
338                      u32 len;
339                      u32 flags;
340                      }) vmxnet3_rx_comp;
341
342 /*
343  * index:
344  *   TX desc index           -- bits 0-11
345  *   ext1                    -- bits 12-31
346  *
347  * flags:
348  *   reserved                -- bits 0-23
349  *   completion type         -- bits 24-30
350  *   generation              -- bit  31
351  */
352 typedef CLIB_PACKED (struct
353                      {
354                      u32 index;
355                      u32 pad[2];
356                      u32 flags;
357                      }) vmxnet3_tx_comp;
358
359 /*
360  * flags[0]:
361  *   length                  -- bits 0-13
362  *   generation              -- bit  14
363  *   reserved                -- bit  15
364  *   descriptor type         -- bit  16
365  *   ext1                    -- bit  17
366  *   MSS, checksum offset    -- bits 18-31
367  * flags[1]:
368  *   header length           -- bits 0-9
369  *   offload mode            -- bits 10-11
370  *   end of packet           -- bit  12
371  *   completion request      -- bit  13
372  *   ext2                    -- bit  14
373  *   vlan tag insertion      -- bit  15
374  *   tag to insert           -- bits 16-31
375  */
376 typedef CLIB_PACKED (struct
377                      {
378                      u64 address;
379                      u32 flags[2];
380                      }) vmxnet3_tx_desc;
381
382 typedef struct
383 {
384   CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
385   u32 *bufs;
386   u32 gen;
387   u16 fill;
388   u16 rid;
389   u16 produce;
390   u16 consume;
391 } vmxnet3_rx_ring;
392
393 typedef struct
394 {
395   CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
396   u64 next;
397   u32 gen;
398 } vmxnet3_rx_comp_ring;
399
400 typedef struct
401 {
402   CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
403   u16 size;
404   u8 int_mode;
405   vmxnet3_rx_ring rx_ring[VMXNET3_RX_RING_SIZE];
406   vmxnet3_rx_desc *rx_desc[VMXNET3_RX_RING_SIZE];
407   vmxnet3_rx_comp *rx_comp;
408   vmxnet3_rx_comp_ring rx_comp_ring;
409 } vmxnet3_rxq_t;
410
411 typedef struct
412 {
413   CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
414   u32 *bufs;
415   u32 gen;
416   u16 produce;
417   u16 consume;
418 } vmxnet3_tx_ring;
419
420 typedef struct
421 {
422   CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
423   u64 next;
424   u32 gen;
425 } vmxnet3_tx_comp_ring;
426
427 typedef struct
428 {
429   CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
430   u16 size;
431   clib_spinlock_t lock;
432
433   vmxnet3_tx_desc *tx_desc;
434   vmxnet3_tx_comp *tx_comp;
435   vmxnet3_tx_ring tx_ring;
436   vmxnet3_tx_comp_ring tx_comp_ring;
437 } vmxnet3_txq_t;
438
439 typedef CLIB_PACKED (struct
440                      {
441                      vmxnet3_queues queues; vmxnet3_shared shared;
442                      }) vmxnet3_dma;
443
444 typedef struct
445 {
446   CLIB_CACHE_LINE_ALIGN_MARK (cacheline0);
447   u32 flags;
448   u32 per_interface_next_index;
449
450   u32 dev_instance;
451   u32 sw_if_index;
452   u32 hw_if_index;
453   vlib_pci_dev_handle_t pci_dev_handle;
454   vlib_pci_addr_t pci_addr;
455   void *bar[2];
456
457   /* queues */
458   vmxnet3_rxq_t *rxqs;
459   vmxnet3_txq_t *txqs;
460
461   u16 num_tx_queues;
462   u16 num_rx_queues;
463   u16 num_intrs;
464
465   u8 version;
466   u8 mac_addr[6];
467
468   /* error */
469   clib_error_t *error;
470
471   vmxnet3_dma *dma;
472
473 } vmxnet3_device_t;
474
475 typedef struct
476 {
477   vmxnet3_device_t *devices;
478   vlib_physmem_region_index_t physmem_region;
479   u32 physmem_region_alloc;
480   u16 msg_id_base;
481 } vmxnet3_main_t;
482
483 extern vmxnet3_main_t vmxnet3_main;
484
485 typedef struct
486 {
487   vlib_pci_addr_t addr;
488   u32 enable_elog;
489   u16 rxq_size;
490   u16 txq_size;
491   /* return */
492   i32 rv;
493   u32 sw_if_index;
494   clib_error_t *error;
495 } vmxnet3_create_if_args_t;
496
497 typedef struct
498 {
499   u32 next_index;
500   u32 hw_if_index;
501   vlib_buffer_t buffer;
502 } vmxnet3_input_trace_t;
503
504 void vmxnet3_create_if (vlib_main_t * vm, vmxnet3_create_if_args_t * args);
505 void vmxnet3_delete_if (vlib_main_t * vm, vmxnet3_device_t * ad);
506
507 extern clib_error_t *vmxnet3_plugin_api_hookup (vlib_main_t * vm);
508 extern vlib_node_registration_t vmxnet3_input_node;
509 extern vnet_device_class_t vmxnet3_device_class;
510
511 /* format.c */
512 format_function_t format_vmxnet3_device;
513 format_function_t format_vmxnet3_device_name;
514 format_function_t format_vmxnet3_input_trace;
515
516 static_always_inline void
517 vmxnet3_reg_write (vmxnet3_device_t * vd, u8 bar, u32 addr, u32 val)
518 {
519   *(volatile u32 *) ((u8 *) vd->bar[bar] + addr) = val;
520 }
521
522 static_always_inline u32
523 vmxnet3_reg_read (vmxnet3_device_t * vd, u8 bar, u32 addr)
524 {
525   return *(volatile u32 *) (vd->bar[bar] + addr);
526 }
527
528 static_always_inline uword
529 vmxnet3_dma_addr (vlib_main_t * vm, vmxnet3_device_t * vd, void *p)
530 {
531   vmxnet3_main_t *vmxm = &vmxnet3_main;
532
533   return (vd->flags & VMXNET3_DEVICE_F_IOVA) ? pointer_to_uword (p) :
534     vlib_physmem_virtual_to_physical (vm, vmxm->physmem_region, p);
535 }
536
537 static_always_inline void
538 vmxnet3_rx_ring_advance_produce (vmxnet3_rxq_t * rxq, vmxnet3_rx_ring * ring)
539 {
540   ring->produce++;
541   if (PREDICT_FALSE (ring->produce == rxq->size))
542     {
543       ring->produce = 0;
544       ring->gen ^= VMXNET3_RXF_GEN;
545     }
546 }
547
548 static_always_inline clib_error_t *
549 vmxnet3_rxq_refill_ring0 (vlib_main_t * vm, vmxnet3_device_t * vd,
550                           vmxnet3_rxq_t * rxq)
551 {
552   vmxnet3_rx_desc *rxd;
553   u16 n_refill, n_alloc;
554   vmxnet3_rx_ring *ring;
555
556   ring = &rxq->rx_ring[0];
557   n_refill = rxq->size - ring->fill;
558
559   if (PREDICT_TRUE (n_refill <= VMXNET3_INPUT_REFILL_THRESHOLD))
560     return 0;
561
562   n_alloc =
563     vlib_buffer_alloc_to_ring (vm, ring->bufs, ring->produce, rxq->size,
564                                n_refill);
565   if (PREDICT_FALSE (n_alloc != n_refill))
566     {
567       if (n_alloc)
568         vlib_buffer_free_from_ring (vm, ring->bufs, ring->produce, rxq->size,
569                                     n_alloc);
570       return clib_error_return (0, "buffer alloc failed");
571     }
572
573   while (n_alloc)
574     {
575       rxd = &rxq->rx_desc[0][ring->produce];
576       rxd->address =
577         vlib_get_buffer_data_physical_address (vm, ring->bufs[ring->produce]);
578       rxd->flags = ring->gen | VLIB_BUFFER_DATA_SIZE;
579
580       vmxnet3_rx_ring_advance_produce (rxq, ring);
581       ring->fill++;
582       n_alloc--;
583     }
584
585   vmxnet3_reg_write (vd, 0, VMXNET3_REG_RXPROD, ring->produce);
586
587   return 0;
588 }
589
590 static_always_inline clib_error_t *
591 vmxnet3_rxq_refill_ring1 (vlib_main_t * vm, vmxnet3_device_t * vd,
592                           vmxnet3_rxq_t * rxq)
593 {
594   vmxnet3_rx_desc *rxd;
595   u16 n_refill, n_alloc;
596   vmxnet3_rx_ring *ring;
597
598   ring = &rxq->rx_ring[1];
599   n_refill = rxq->size - ring->fill;
600
601   if (PREDICT_TRUE (n_refill <= VMXNET3_INPUT_REFILL_THRESHOLD))
602     return 0;
603
604   n_alloc =
605     vlib_buffer_alloc_to_ring (vm, ring->bufs, ring->produce, rxq->size,
606                                n_refill);
607   if (PREDICT_FALSE (n_alloc != n_refill))
608     {
609       if (n_alloc)
610         vlib_buffer_free_from_ring (vm, ring->bufs, ring->produce, rxq->size,
611                                     n_alloc);
612       return clib_error_return (0, "buffer alloc failed");
613     }
614
615   while (n_alloc)
616     {
617       rxd = &rxq->rx_desc[1][ring->produce];
618       rxd->address =
619         vlib_get_buffer_data_physical_address (vm, ring->bufs[ring->produce]);
620       rxd->flags = ring->gen | VLIB_BUFFER_DATA_SIZE | VMXNET3_RXF_BTYPE;
621
622       vmxnet3_rx_ring_advance_produce (rxq, ring);
623       ring->fill++;
624       n_alloc--;
625     }
626
627   vmxnet3_reg_write (vd, 0, VMXNET3_REG_RXPROD2, ring->produce);
628
629   return 0;
630 }
631
632 #endif /* __included_vmnet_vmnet_h__ */
633 /*
634  * fd.io coding-style-patch-verification: ON
635  *
636  * Local Variables:
637  * eval: (c-set-style "gnu")
638  * End:
639  */