hc
2024-08-16 a24a44ff9ca902811b99aa9663d697cf452e08ef
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _SPARC64_VIO_H
#define _SPARC64_VIO_H
 
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/mod_devicetable.h>
#include <linux/timer.h>
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/list.h>
#include <linux/log2.h>
 
#include <asm/ldc.h>
#include <asm/mdesc.h>
 
struct vio_msg_tag {
   u8            type;
#define VIO_TYPE_CTRL        0x01
#define VIO_TYPE_DATA        0x02
#define VIO_TYPE_ERR        0x04
 
   u8            stype;
#define VIO_SUBTYPE_INFO    0x01
#define VIO_SUBTYPE_ACK        0x02
#define VIO_SUBTYPE_NACK    0x04
 
   u16            stype_env;
#define VIO_VER_INFO        0x0001
#define VIO_ATTR_INFO        0x0002
#define VIO_DRING_REG        0x0003
#define VIO_DRING_UNREG        0x0004
#define VIO_RDX            0x0005
#define VIO_PKT_DATA        0x0040
#define VIO_DESC_DATA        0x0041
#define VIO_DRING_DATA        0x0042
#define VNET_MCAST_INFO        0x0101
 
   u32        sid;
};
 
struct vio_rdx {
   struct vio_msg_tag    tag;
   u64            resv[6];
};
 
struct vio_ver_info {
   struct vio_msg_tag    tag;
   u16            major;
   u16            minor;
   u8            dev_class;
#define VDEV_NETWORK        0x01
#define VDEV_NETWORK_SWITCH    0x02
#define VDEV_DISK        0x03
#define VDEV_DISK_SERVER    0x04
#define VDEV_CONSOLE_CON    0x05
 
   u8            resv1[3];
   u64            resv2[5];
};
 
struct vio_dring_register {
   struct vio_msg_tag    tag;
   u64            dring_ident;
   u32            num_descr;
   u32            descr_size;
   u16            options;
#define VIO_TX_DRING        0x0001
#define VIO_RX_DRING        0x0002
#define VIO_RX_DRING_DATA    0x0004
   u16            resv;
   u32            num_cookies;
   struct ldc_trans_cookie    cookies[0];
};
 
struct vio_dring_unregister {
   struct vio_msg_tag    tag;
   u64            dring_ident;
   u64            resv[5];
};
 
/* Data transfer modes */
#define VIO_PKT_MODE        0x01 /* Packet based transfer    */
#define VIO_DESC_MODE        0x02 /* In-band descriptors    */
#define VIO_DRING_MODE        0x03 /* Descriptor rings    */
/* in vers >= 1.2, VIO_DRING_MODE is 0x04 and transfer mode is a bitmask */
#define VIO_NEW_DRING_MODE    0x04
 
struct vio_dring_data {
   struct vio_msg_tag    tag;
   u64            seq;
   u64            dring_ident;
   u32            start_idx;
   u32            end_idx;
   u8            state;
#define VIO_DRING_ACTIVE    0x01
#define VIO_DRING_STOPPED    0x02
 
   u8            __pad1;
   u16            __pad2;
   u32            __pad3;
   u64            __par4[2];
};
 
struct vio_dring_hdr {
   u8            state;
#define VIO_DESC_FREE        0x01
#define VIO_DESC_READY        0x02
#define VIO_DESC_ACCEPTED    0x03
#define VIO_DESC_DONE        0x04
   u8            ack;
#define VIO_ACK_ENABLE        0x01
#define VIO_ACK_DISABLE        0x00
 
   u16            __pad1;
   u32            __pad2;
};
 
/* VIO disk specific structures and defines */
struct vio_disk_attr_info {
   struct vio_msg_tag    tag;
   u8            xfer_mode;
   u8            vdisk_type;
#define VD_DISK_TYPE_SLICE    0x01 /* Slice in block device    */
#define VD_DISK_TYPE_DISK    0x02 /* Entire block device    */
   u8            vdisk_mtype;        /* v1.1 */
#define VD_MEDIA_TYPE_FIXED    0x01 /* Fixed device */
#define VD_MEDIA_TYPE_CD    0x02 /* CD Device    */
#define VD_MEDIA_TYPE_DVD    0x03 /* DVD Device   */
   u8            resv1;
   u32            vdisk_block_size;
   u64            operations;
   u64            vdisk_size;        /* v1.1 */
   u64            max_xfer_size;
   u32            phys_block_size;    /* v1.2 */
   u32            resv2;
   u64            resv3[1];
};
 
struct vio_disk_desc {
   struct vio_dring_hdr    hdr;
   u64            req_id;
   u8            operation;
#define VD_OP_BREAD        0x01 /* Block read            */
#define VD_OP_BWRITE        0x02 /* Block write            */
#define VD_OP_FLUSH        0x03 /* Flush disk contents        */
#define VD_OP_GET_WCE        0x04 /* Get write-cache status        */
#define VD_OP_SET_WCE        0x05 /* Enable/disable write-cache    */
#define VD_OP_GET_VTOC        0x06 /* Get VTOC            */
#define VD_OP_SET_VTOC        0x07 /* Set VTOC            */
#define VD_OP_GET_DISKGEOM    0x08 /* Get disk geometry        */
#define VD_OP_SET_DISKGEOM    0x09 /* Set disk geometry        */
#define VD_OP_SCSICMD        0x0a /* SCSI control command        */
#define VD_OP_GET_DEVID        0x0b /* Get device ID            */
#define VD_OP_GET_EFI        0x0c /* Get EFI                */
#define VD_OP_SET_EFI        0x0d /* Set EFI                */
   u8            slice;
   u16            resv1;
   u32            status;
   u64            offset;
   u64            size;
   u32            ncookies;
   u32            resv2;
   struct ldc_trans_cookie    cookies[0];
};
 
#define VIO_DISK_VNAME_LEN    8
#define VIO_DISK_ALABEL_LEN    128
#define VIO_DISK_NUM_PART    8
 
struct vio_disk_vtoc {
   u8            volume_name[VIO_DISK_VNAME_LEN];
   u16            sector_size;
   u16            num_partitions;
   u8            ascii_label[VIO_DISK_ALABEL_LEN];
   struct {
       u16        id;
       u16        perm_flags;
       u32        resv;
       u64        start_block;
       u64        num_blocks;
   } partitions[VIO_DISK_NUM_PART];
};
 
struct vio_disk_geom {
   u16            num_cyl; /* Num data cylinders        */
   u16            alt_cyl; /* Num alternate cylinders    */
   u16            beg_cyl; /* Cyl off of fixed head area    */
   u16            num_hd;  /* Num heads            */
   u16            num_sec; /* Num sectors            */
   u16            ifact;   /* Interleave factor        */
   u16            apc;     /* Alts per cylinder (SCSI)    */
   u16            rpm;     /* Revolutions per minute    */
   u16            phy_cyl; /* Num physical cylinders    */
   u16            wr_skip; /* Num sects to skip, writes    */
   u16            rd_skip; /* Num sects to skip, writes    */
};
 
struct vio_disk_devid {
   u16            resv;
   u16            type;
   u32            len;
   char            id[0];
};
 
struct vio_disk_efi {
   u64            lba;
   u64            len;
   char            data[0];
};
 
/* VIO net specific structures and defines */
struct vio_net_attr_info {
   struct vio_msg_tag    tag;
   u8            xfer_mode;
   u8            addr_type;
#define VNET_ADDR_ETHERMAC    0x01
   u16            ack_freq;
   u8            plnk_updt;
#define PHYSLINK_UPDATE_NONE        0x00
#define PHYSLINK_UPDATE_STATE        0x01
#define PHYSLINK_UPDATE_STATE_ACK    0x02
#define PHYSLINK_UPDATE_STATE_NACK    0x03
   u8            options;
   u16            resv1;
   u64            addr;
   u64            mtu;
   u16            cflags;
#define VNET_LSO_IPV4_CAPAB        0x0001
   u16            ipv4_lso_maxlen;
   u32            resv2;
   u64            resv3[2];
};
 
#define VNET_NUM_MCAST        7
 
struct vio_net_mcast_info {
   struct vio_msg_tag    tag;
   u8            set;
   u8            count;
   u8            mcast_addr[VNET_NUM_MCAST * 6];
   u32            resv;
};
 
struct vio_net_desc {
   struct vio_dring_hdr    hdr;
   u32            size;
   u32            ncookies;
   struct ldc_trans_cookie    cookies[0];
};
 
struct vio_net_dext {
   u8        flags;
#define VNET_PKT_HASH            0x01
#define    VNET_PKT_HCK_IPV4_HDRCKSUM    0x02
#define    VNET_PKT_HCK_FULLCKSUM        0x04
#define    VNET_PKT_IPV4_LSO        0x08
#define    VNET_PKT_HCK_IPV4_HDRCKSUM_OK    0x10
#define    VNET_PKT_HCK_FULLCKSUM_OK    0x20
 
   u8        vnet_hashval;
   u16        ipv4_lso_mss;
   u32        resv3;
};
 
static inline struct vio_net_dext *vio_net_ext(struct vio_net_desc *desc)
{
   return (struct vio_net_dext *)&desc->cookies[2];
}
 
#define VIO_MAX_RING_COOKIES    24
 
struct vio_dring_state {
   u64            ident;
   void            *base;
   u64            snd_nxt;
   u64            rcv_nxt;
   u32            entry_size;
   u32            num_entries;
   u32            prod;
   u32            cons;
   u32            pending;
   int            ncookies;
   struct ldc_trans_cookie    cookies[VIO_MAX_RING_COOKIES];
};
 
#define VIO_TAG_SIZE        ((int)sizeof(struct vio_msg_tag))
#define VIO_VCC_MTU_SIZE    (LDC_PACKET_SIZE - VIO_TAG_SIZE)
 
struct vio_vcc {
   struct vio_msg_tag    tag;
   char            data[VIO_VCC_MTU_SIZE];
};
 
static inline void *vio_dring_cur(struct vio_dring_state *dr)
{
   return dr->base + (dr->entry_size * dr->prod);
}
 
static inline void *vio_dring_entry(struct vio_dring_state *dr,
                   unsigned int index)
{
   return dr->base + (dr->entry_size * index);
}
 
static inline u32 vio_dring_avail(struct vio_dring_state *dr,
                 unsigned int ring_size)
{
   return (dr->pending -
       ((dr->prod - dr->cons) & (ring_size - 1)) - 1);
}
 
static inline u32 vio_dring_next(struct vio_dring_state *dr, u32 index)
{
   if (++index == dr->num_entries)
       index = 0;
   return index;
}
 
static inline u32 vio_dring_prev(struct vio_dring_state *dr, u32 index)
{
   if (index == 0)
       return dr->num_entries - 1;
   else
       return index - 1;
}
 
#define VIO_MAX_TYPE_LEN    32
#define VIO_MAX_NAME_LEN    32
#define VIO_MAX_COMPAT_LEN    64
 
struct vio_dev {
   u64            mp;
   struct device_node    *dp;
 
   char            node_name[VIO_MAX_NAME_LEN];
   char            type[VIO_MAX_TYPE_LEN];
   char            compat[VIO_MAX_COMPAT_LEN];
   int            compat_len;
 
   u64            dev_no;
 
   unsigned long        port_id;
   unsigned long        channel_id;
 
   unsigned int        tx_irq;
   unsigned int        rx_irq;
   u64            rx_ino;
   u64            tx_ino;
 
   /* Handle to the root of "channel-devices" sub-tree in MDESC */
   u64            cdev_handle;
 
   /* MD specific data used to identify the vdev in MD */
   union md_node_info    md_node_info;
 
   struct device        dev;
};
 
struct vio_driver {
   const char            *name;
   struct list_head        node;
   const struct vio_device_id    *id_table;
   int (*probe)(struct vio_dev *dev, const struct vio_device_id *id);
   int (*remove)(struct vio_dev *dev);
   void (*shutdown)(struct vio_dev *dev);
   unsigned long            driver_data;
   struct device_driver        driver;
   bool                no_irq;
};
 
struct vio_version {
   u16        major;
   u16        minor;
};
 
struct vio_driver_state;
struct vio_driver_ops {
   int    (*send_attr)(struct vio_driver_state *vio);
   int    (*handle_attr)(struct vio_driver_state *vio, void *pkt);
   void    (*handshake_complete)(struct vio_driver_state *vio);
};
 
struct vio_completion {
   struct completion    com;
   int            err;
   int            waiting_for;
};
 
struct vio_driver_state {
   /* Protects VIO handshake and, optionally, driver private state.  */
   spinlock_t        lock;
 
   struct ldc_channel    *lp;
 
   u32            _peer_sid;
   u32            _local_sid;
   struct vio_dring_state    drings[2];
#define VIO_DRIVER_TX_RING    0
#define VIO_DRIVER_RX_RING    1
 
   u8            hs_state;
#define VIO_HS_INVALID        0x00
#define VIO_HS_GOTVERS        0x01
#define VIO_HS_GOT_ATTR        0x04
#define VIO_HS_SENT_DREG    0x08
#define VIO_HS_SENT_RDX        0x10
#define VIO_HS_GOT_RDX_ACK    0x20
#define VIO_HS_GOT_RDX        0x40
#define VIO_HS_SENT_RDX_ACK    0x80
#define VIO_HS_COMPLETE        (VIO_HS_GOT_RDX_ACK | VIO_HS_SENT_RDX_ACK)
 
   u8            dev_class;
 
   u8            dr_state;
#define VIO_DR_STATE_TXREG    0x01
#define VIO_DR_STATE_RXREG    0x02
#define VIO_DR_STATE_TXREQ    0x10
#define VIO_DR_STATE_RXREQ    0x20
 
   u8            debug;
#define VIO_DEBUG_HS        0x01
#define VIO_DEBUG_DATA        0x02
 
   void            *desc_buf;
   unsigned int        desc_buf_len;
 
   struct vio_completion    *cmp;
 
   struct vio_dev        *vdev;
 
   struct timer_list    timer;
 
   struct vio_version    ver;
 
   struct vio_version    *ver_table;
   int            ver_table_entries;
 
   char            *name;
 
   struct vio_driver_ops    *ops;
};
 
static inline bool vio_version_before(struct vio_driver_state *vio,
                     u16 major, u16 minor)
{
   u32 have = (u32)vio->ver.major << 16 | vio->ver.minor;
   u32 want = (u32)major << 16 | minor;
 
   return have < want;
}
 
static inline bool vio_version_after(struct vio_driver_state *vio,
                     u16 major, u16 minor)
{
   u32 have = (u32)vio->ver.major << 16 | vio->ver.minor;
   u32 want = (u32)major << 16 | minor;
 
   return have > want;
}
 
static inline bool vio_version_after_eq(struct vio_driver_state *vio,
                   u16 major, u16 minor)
{
   u32 have = (u32)vio->ver.major << 16 | vio->ver.minor;
   u32 want = (u32)major << 16 | minor;
 
   return have >= want;
}
 
#define viodbg(TYPE, f, a...) \
do {    if (vio->debug & VIO_DEBUG_##TYPE) \
       printk(KERN_INFO "vio: ID[%lu] " f, \
              vio->vdev->channel_id, ## a); \
} while (0)
 
int __vio_register_driver(struct vio_driver *drv, struct module *owner,
                const char *mod_name);
/*
 * vio_register_driver must be a macro so that KBUILD_MODNAME can be expanded
 */
#define vio_register_driver(driver)        \
   __vio_register_driver(driver, THIS_MODULE, KBUILD_MODNAME)
void vio_unregister_driver(struct vio_driver *drv);
 
static inline struct vio_driver *to_vio_driver(struct device_driver *drv)
{
   return container_of(drv, struct vio_driver, driver);
}
 
static inline struct vio_dev *to_vio_dev(struct device *dev)
{
   return container_of(dev, struct vio_dev, dev);
}
 
int vio_ldc_send(struct vio_driver_state *vio, void *data, int len);
void vio_link_state_change(struct vio_driver_state *vio, int event);
void vio_conn_reset(struct vio_driver_state *vio);
int vio_control_pkt_engine(struct vio_driver_state *vio, void *pkt);
int vio_validate_sid(struct vio_driver_state *vio,
            struct vio_msg_tag *tp);
u32 vio_send_sid(struct vio_driver_state *vio);
int vio_ldc_alloc(struct vio_driver_state *vio,
         struct ldc_channel_config *base_cfg, void *event_arg);
void vio_ldc_free(struct vio_driver_state *vio);
int vio_driver_init(struct vio_driver_state *vio, struct vio_dev *vdev,
           u8 dev_class, struct vio_version *ver_table,
           int ver_table_size, struct vio_driver_ops *ops,
           char *name);
 
void vio_port_up(struct vio_driver_state *vio);
int vio_set_intr(unsigned long dev_ino, int state);
u64 vio_vdev_node(struct mdesc_handle *hp, struct vio_dev *vdev);
 
#endif /* _SPARC64_VIO_H */