xref: /OK3568_Linux_fs/kernel/drivers/scsi/aic94xx/aic94xx_reg.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Aic94xx SAS/SATA driver register access.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
6*4882a593Smuzhiyun  * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/pci.h>
10*4882a593Smuzhiyun #include "aic94xx_reg.h"
11*4882a593Smuzhiyun #include "aic94xx.h"
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun /* Writing to device address space.
14*4882a593Smuzhiyun  * Offset comes before value to remind that the operation of
15*4882a593Smuzhiyun  * this function is *offs = val.
16*4882a593Smuzhiyun  */
asd_write_byte(struct asd_ha_struct * asd_ha,unsigned long offs,u8 val)17*4882a593Smuzhiyun static void asd_write_byte(struct asd_ha_struct *asd_ha,
18*4882a593Smuzhiyun 			   unsigned long offs, u8 val)
19*4882a593Smuzhiyun {
20*4882a593Smuzhiyun 	if (unlikely(asd_ha->iospace))
21*4882a593Smuzhiyun 		outb(val,
22*4882a593Smuzhiyun 		     (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF));
23*4882a593Smuzhiyun 	else
24*4882a593Smuzhiyun 		writeb(val, asd_ha->io_handle[0].addr + offs);
25*4882a593Smuzhiyun 	wmb();
26*4882a593Smuzhiyun }
27*4882a593Smuzhiyun 
asd_write_word(struct asd_ha_struct * asd_ha,unsigned long offs,u16 val)28*4882a593Smuzhiyun static void asd_write_word(struct asd_ha_struct *asd_ha,
29*4882a593Smuzhiyun 			   unsigned long offs, u16 val)
30*4882a593Smuzhiyun {
31*4882a593Smuzhiyun 	if (unlikely(asd_ha->iospace))
32*4882a593Smuzhiyun 		outw(val,
33*4882a593Smuzhiyun 		     (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF));
34*4882a593Smuzhiyun 	else
35*4882a593Smuzhiyun 		writew(val, asd_ha->io_handle[0].addr + offs);
36*4882a593Smuzhiyun 	wmb();
37*4882a593Smuzhiyun }
38*4882a593Smuzhiyun 
asd_write_dword(struct asd_ha_struct * asd_ha,unsigned long offs,u32 val)39*4882a593Smuzhiyun static void asd_write_dword(struct asd_ha_struct *asd_ha,
40*4882a593Smuzhiyun 			    unsigned long offs, u32 val)
41*4882a593Smuzhiyun {
42*4882a593Smuzhiyun 	if (unlikely(asd_ha->iospace))
43*4882a593Smuzhiyun 		outl(val,
44*4882a593Smuzhiyun 		     (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF));
45*4882a593Smuzhiyun 	else
46*4882a593Smuzhiyun 		writel(val, asd_ha->io_handle[0].addr + offs);
47*4882a593Smuzhiyun 	wmb();
48*4882a593Smuzhiyun }
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun /* Reading from device address space.
51*4882a593Smuzhiyun  */
asd_read_byte(struct asd_ha_struct * asd_ha,unsigned long offs)52*4882a593Smuzhiyun static u8 asd_read_byte(struct asd_ha_struct *asd_ha, unsigned long offs)
53*4882a593Smuzhiyun {
54*4882a593Smuzhiyun 	u8 val;
55*4882a593Smuzhiyun 	if (unlikely(asd_ha->iospace))
56*4882a593Smuzhiyun 		val = inb((unsigned long) asd_ha->io_handle[0].addr
57*4882a593Smuzhiyun 			  + (offs & 0xFF));
58*4882a593Smuzhiyun 	else
59*4882a593Smuzhiyun 		val = readb(asd_ha->io_handle[0].addr + offs);
60*4882a593Smuzhiyun 	rmb();
61*4882a593Smuzhiyun 	return val;
62*4882a593Smuzhiyun }
63*4882a593Smuzhiyun 
asd_read_word(struct asd_ha_struct * asd_ha,unsigned long offs)64*4882a593Smuzhiyun static u16 asd_read_word(struct asd_ha_struct *asd_ha,
65*4882a593Smuzhiyun 			 unsigned long offs)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun 	u16 val;
68*4882a593Smuzhiyun 	if (unlikely(asd_ha->iospace))
69*4882a593Smuzhiyun 		val = inw((unsigned long)asd_ha->io_handle[0].addr
70*4882a593Smuzhiyun 			  + (offs & 0xFF));
71*4882a593Smuzhiyun 	else
72*4882a593Smuzhiyun 		val = readw(asd_ha->io_handle[0].addr + offs);
73*4882a593Smuzhiyun 	rmb();
74*4882a593Smuzhiyun 	return val;
75*4882a593Smuzhiyun }
76*4882a593Smuzhiyun 
asd_read_dword(struct asd_ha_struct * asd_ha,unsigned long offs)77*4882a593Smuzhiyun static u32 asd_read_dword(struct asd_ha_struct *asd_ha,
78*4882a593Smuzhiyun 			  unsigned long offs)
79*4882a593Smuzhiyun {
80*4882a593Smuzhiyun 	u32 val;
81*4882a593Smuzhiyun 	if (unlikely(asd_ha->iospace))
82*4882a593Smuzhiyun 		val = inl((unsigned long) asd_ha->io_handle[0].addr
83*4882a593Smuzhiyun 			  + (offs & 0xFF));
84*4882a593Smuzhiyun 	else
85*4882a593Smuzhiyun 		val = readl(asd_ha->io_handle[0].addr + offs);
86*4882a593Smuzhiyun 	rmb();
87*4882a593Smuzhiyun 	return val;
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun 
asd_mem_offs_swa(void)90*4882a593Smuzhiyun static inline u32 asd_mem_offs_swa(void)
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun 	return 0;
93*4882a593Smuzhiyun }
94*4882a593Smuzhiyun 
asd_mem_offs_swc(void)95*4882a593Smuzhiyun static inline u32 asd_mem_offs_swc(void)
96*4882a593Smuzhiyun {
97*4882a593Smuzhiyun 	return asd_mem_offs_swa() + MBAR0_SWA_SIZE;
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun 
asd_mem_offs_swb(void)100*4882a593Smuzhiyun static inline u32 asd_mem_offs_swb(void)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun 	return asd_mem_offs_swc() + MBAR0_SWC_SIZE + 0x20;
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun /* We know that the register wanted is in the range
106*4882a593Smuzhiyun  * of the sliding window.
107*4882a593Smuzhiyun  */
108*4882a593Smuzhiyun #define ASD_READ_SW(ww, type, ord)					\
109*4882a593Smuzhiyun static type asd_read_##ww##_##ord(struct asd_ha_struct *asd_ha,		\
110*4882a593Smuzhiyun 				   u32 reg)				\
111*4882a593Smuzhiyun {									\
112*4882a593Smuzhiyun 	struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0];	\
113*4882a593Smuzhiyun 	u32 map_offs = (reg - io_handle->ww##_base) + asd_mem_offs_##ww();\
114*4882a593Smuzhiyun 	return asd_read_##ord(asd_ha, (unsigned long)map_offs);	\
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun #define ASD_WRITE_SW(ww, type, ord)					\
118*4882a593Smuzhiyun static void asd_write_##ww##_##ord(struct asd_ha_struct *asd_ha,	\
119*4882a593Smuzhiyun 				    u32 reg, type val)			\
120*4882a593Smuzhiyun {									\
121*4882a593Smuzhiyun 	struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0];	\
122*4882a593Smuzhiyun 	u32 map_offs = (reg - io_handle->ww##_base) + asd_mem_offs_##ww();\
123*4882a593Smuzhiyun 	asd_write_##ord(asd_ha, (unsigned long)map_offs, val);		\
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun ASD_READ_SW(swa, u8,  byte);
127*4882a593Smuzhiyun ASD_READ_SW(swa, u16, word);
128*4882a593Smuzhiyun ASD_READ_SW(swa, u32, dword);
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun ASD_READ_SW(swb, u8,  byte);
131*4882a593Smuzhiyun ASD_READ_SW(swb, u16, word);
132*4882a593Smuzhiyun ASD_READ_SW(swb, u32, dword);
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun ASD_READ_SW(swc, u8,  byte);
135*4882a593Smuzhiyun ASD_READ_SW(swc, u16, word);
136*4882a593Smuzhiyun ASD_READ_SW(swc, u32, dword);
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun ASD_WRITE_SW(swa, u8,  byte);
139*4882a593Smuzhiyun ASD_WRITE_SW(swa, u16, word);
140*4882a593Smuzhiyun ASD_WRITE_SW(swa, u32, dword);
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun ASD_WRITE_SW(swb, u8,  byte);
143*4882a593Smuzhiyun ASD_WRITE_SW(swb, u16, word);
144*4882a593Smuzhiyun ASD_WRITE_SW(swb, u32, dword);
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun ASD_WRITE_SW(swc, u8,  byte);
147*4882a593Smuzhiyun ASD_WRITE_SW(swc, u16, word);
148*4882a593Smuzhiyun ASD_WRITE_SW(swc, u32, dword);
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun /*
151*4882a593Smuzhiyun  * A word about sliding windows:
152*4882a593Smuzhiyun  * MBAR0 is divided into sliding windows A, C and B, in that order.
153*4882a593Smuzhiyun  * SWA starts at offset 0 of MBAR0, up to 0x57, with size 0x58 bytes.
154*4882a593Smuzhiyun  * SWC starts at offset 0x58 of MBAR0, up to 0x60, with size 0x8 bytes.
155*4882a593Smuzhiyun  * From 0x60 to 0x7F, we have a copy of PCI config space 0x60-0x7F.
156*4882a593Smuzhiyun  * SWB starts at offset 0x80 of MBAR0 and extends to the end of MBAR0.
157*4882a593Smuzhiyun  * See asd_init_sw() in aic94xx_hwi.c
158*4882a593Smuzhiyun  *
159*4882a593Smuzhiyun  * We map the most common registers we'd access of the internal 4GB
160*4882a593Smuzhiyun  * host adapter memory space.  If a register/internal memory location
161*4882a593Smuzhiyun  * is wanted which is not mapped, we slide SWB, by paging it,
162*4882a593Smuzhiyun  * see asd_move_swb() in aic94xx_reg.c.
163*4882a593Smuzhiyun  */
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun /**
166*4882a593Smuzhiyun  * asd_move_swb -- move sliding window B
167*4882a593Smuzhiyun  * @asd_ha: pointer to host adapter structure
168*4882a593Smuzhiyun  * @reg: register desired to be within range of the new window
169*4882a593Smuzhiyun  */
asd_move_swb(struct asd_ha_struct * asd_ha,u32 reg)170*4882a593Smuzhiyun static void asd_move_swb(struct asd_ha_struct *asd_ha, u32 reg)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun 	u32 base = reg & ~(MBAR0_SWB_SIZE-1);
173*4882a593Smuzhiyun 	pci_write_config_dword(asd_ha->pcidev, PCI_CONF_MBAR0_SWB, base);
174*4882a593Smuzhiyun 	asd_ha->io_handle[0].swb_base = base;
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun 
__asd_write_reg_byte(struct asd_ha_struct * asd_ha,u32 reg,u8 val)177*4882a593Smuzhiyun static void __asd_write_reg_byte(struct asd_ha_struct *asd_ha, u32 reg, u8 val)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun 	struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0];
180*4882a593Smuzhiyun 	BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);
181*4882a593Smuzhiyun 	if (io_handle->swa_base <= reg
182*4882a593Smuzhiyun 	    && reg < io_handle->swa_base + MBAR0_SWA_SIZE)
183*4882a593Smuzhiyun 		asd_write_swa_byte (asd_ha, reg,val);
184*4882a593Smuzhiyun 	else if (io_handle->swb_base <= reg
185*4882a593Smuzhiyun 		 && reg < io_handle->swb_base + MBAR0_SWB_SIZE)
186*4882a593Smuzhiyun 		asd_write_swb_byte (asd_ha, reg, val);
187*4882a593Smuzhiyun 	else if (io_handle->swc_base <= reg
188*4882a593Smuzhiyun 		 && reg < io_handle->swc_base + MBAR0_SWC_SIZE)
189*4882a593Smuzhiyun 		asd_write_swc_byte (asd_ha, reg, val);
190*4882a593Smuzhiyun 	else {
191*4882a593Smuzhiyun 		/* Ok, we have to move SWB */
192*4882a593Smuzhiyun 		asd_move_swb(asd_ha, reg);
193*4882a593Smuzhiyun 		asd_write_swb_byte (asd_ha, reg, val);
194*4882a593Smuzhiyun 	}
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun #define ASD_WRITE_REG(type, ord)                                  \
198*4882a593Smuzhiyun void asd_write_reg_##ord (struct asd_ha_struct *asd_ha, u32 reg, type val)\
199*4882a593Smuzhiyun {                                                                 \
200*4882a593Smuzhiyun 	struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; \
201*4882a593Smuzhiyun 	unsigned long flags;                                      \
202*4882a593Smuzhiyun 	BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);         \
203*4882a593Smuzhiyun 	spin_lock_irqsave(&asd_ha->iolock, flags);                \
204*4882a593Smuzhiyun 	if (io_handle->swa_base <= reg                            \
205*4882a593Smuzhiyun 	    && reg < io_handle->swa_base + MBAR0_SWA_SIZE)        \
206*4882a593Smuzhiyun 		asd_write_swa_##ord (asd_ha, reg,val);            \
207*4882a593Smuzhiyun 	else if (io_handle->swb_base <= reg                       \
208*4882a593Smuzhiyun 		 && reg < io_handle->swb_base + MBAR0_SWB_SIZE)   \
209*4882a593Smuzhiyun 		asd_write_swb_##ord (asd_ha, reg, val);           \
210*4882a593Smuzhiyun 	else if (io_handle->swc_base <= reg                       \
211*4882a593Smuzhiyun 		 && reg < io_handle->swc_base + MBAR0_SWC_SIZE)   \
212*4882a593Smuzhiyun 		asd_write_swc_##ord (asd_ha, reg, val);           \
213*4882a593Smuzhiyun 	else {                                                    \
214*4882a593Smuzhiyun 		/* Ok, we have to move SWB */                     \
215*4882a593Smuzhiyun 		asd_move_swb(asd_ha, reg);                        \
216*4882a593Smuzhiyun 		asd_write_swb_##ord (asd_ha, reg, val);           \
217*4882a593Smuzhiyun 	}                                                         \
218*4882a593Smuzhiyun 	spin_unlock_irqrestore(&asd_ha->iolock, flags);           \
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun ASD_WRITE_REG(u8, byte);
222*4882a593Smuzhiyun ASD_WRITE_REG(u16,word);
223*4882a593Smuzhiyun ASD_WRITE_REG(u32,dword);
224*4882a593Smuzhiyun 
__asd_read_reg_byte(struct asd_ha_struct * asd_ha,u32 reg)225*4882a593Smuzhiyun static u8 __asd_read_reg_byte(struct asd_ha_struct *asd_ha, u32 reg)
226*4882a593Smuzhiyun {
227*4882a593Smuzhiyun 	struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0];
228*4882a593Smuzhiyun 	u8 val;
229*4882a593Smuzhiyun 	BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);
230*4882a593Smuzhiyun 	if (io_handle->swa_base <= reg
231*4882a593Smuzhiyun 	    && reg < io_handle->swa_base + MBAR0_SWA_SIZE)
232*4882a593Smuzhiyun 		val = asd_read_swa_byte (asd_ha, reg);
233*4882a593Smuzhiyun 	else if (io_handle->swb_base <= reg
234*4882a593Smuzhiyun 		 && reg < io_handle->swb_base + MBAR0_SWB_SIZE)
235*4882a593Smuzhiyun 		val = asd_read_swb_byte (asd_ha, reg);
236*4882a593Smuzhiyun 	else if (io_handle->swc_base <= reg
237*4882a593Smuzhiyun 		 && reg < io_handle->swc_base + MBAR0_SWC_SIZE)
238*4882a593Smuzhiyun 		val = asd_read_swc_byte (asd_ha, reg);
239*4882a593Smuzhiyun 	else {
240*4882a593Smuzhiyun 		/* Ok, we have to move SWB */
241*4882a593Smuzhiyun 		asd_move_swb(asd_ha, reg);
242*4882a593Smuzhiyun 		val = asd_read_swb_byte (asd_ha, reg);
243*4882a593Smuzhiyun 	}
244*4882a593Smuzhiyun 	return val;
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun #define ASD_READ_REG(type, ord)                                   \
248*4882a593Smuzhiyun type asd_read_reg_##ord (struct asd_ha_struct *asd_ha, u32 reg)   \
249*4882a593Smuzhiyun {                                                                 \
250*4882a593Smuzhiyun 	struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; \
251*4882a593Smuzhiyun 	type val;                                                 \
252*4882a593Smuzhiyun 	unsigned long flags;                                      \
253*4882a593Smuzhiyun 	BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR);         \
254*4882a593Smuzhiyun 	spin_lock_irqsave(&asd_ha->iolock, flags);                \
255*4882a593Smuzhiyun 	if (io_handle->swa_base <= reg                            \
256*4882a593Smuzhiyun 	    && reg < io_handle->swa_base + MBAR0_SWA_SIZE)        \
257*4882a593Smuzhiyun 		val = asd_read_swa_##ord (asd_ha, reg);           \
258*4882a593Smuzhiyun 	else if (io_handle->swb_base <= reg                       \
259*4882a593Smuzhiyun 		 && reg < io_handle->swb_base + MBAR0_SWB_SIZE)   \
260*4882a593Smuzhiyun 		val = asd_read_swb_##ord (asd_ha, reg);           \
261*4882a593Smuzhiyun 	else if (io_handle->swc_base <= reg                       \
262*4882a593Smuzhiyun 		 && reg < io_handle->swc_base + MBAR0_SWC_SIZE)   \
263*4882a593Smuzhiyun 		val = asd_read_swc_##ord (asd_ha, reg);           \
264*4882a593Smuzhiyun 	else {                                                    \
265*4882a593Smuzhiyun 		/* Ok, we have to move SWB */                     \
266*4882a593Smuzhiyun 		asd_move_swb(asd_ha, reg);                        \
267*4882a593Smuzhiyun 		val = asd_read_swb_##ord (asd_ha, reg);           \
268*4882a593Smuzhiyun 	}                                                         \
269*4882a593Smuzhiyun 	spin_unlock_irqrestore(&asd_ha->iolock, flags);           \
270*4882a593Smuzhiyun 	return val;                                               \
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun ASD_READ_REG(u8, byte);
274*4882a593Smuzhiyun ASD_READ_REG(u16,word);
275*4882a593Smuzhiyun ASD_READ_REG(u32,dword);
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun /**
278*4882a593Smuzhiyun  * asd_read_reg_string -- read a string of bytes from io space memory
279*4882a593Smuzhiyun  * @asd_ha: pointer to host adapter structure
280*4882a593Smuzhiyun  * @dst: pointer to a destination buffer where data will be written to
281*4882a593Smuzhiyun  * @offs: start offset (register) to read from
282*4882a593Smuzhiyun  * @count: number of bytes to read
283*4882a593Smuzhiyun  */
asd_read_reg_string(struct asd_ha_struct * asd_ha,void * dst,u32 offs,int count)284*4882a593Smuzhiyun void asd_read_reg_string(struct asd_ha_struct *asd_ha, void *dst,
285*4882a593Smuzhiyun 			 u32 offs, int count)
286*4882a593Smuzhiyun {
287*4882a593Smuzhiyun 	u8 *p = dst;
288*4882a593Smuzhiyun 	unsigned long flags;
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	spin_lock_irqsave(&asd_ha->iolock, flags);
291*4882a593Smuzhiyun 	for ( ; count > 0; count--, offs++, p++)
292*4882a593Smuzhiyun 		*p = __asd_read_reg_byte(asd_ha, offs);
293*4882a593Smuzhiyun 	spin_unlock_irqrestore(&asd_ha->iolock, flags);
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun /**
297*4882a593Smuzhiyun  * asd_write_reg_string -- write a string of bytes to io space memory
298*4882a593Smuzhiyun  * @asd_ha: pointer to host adapter structure
299*4882a593Smuzhiyun  * @src: pointer to source buffer where data will be read from
300*4882a593Smuzhiyun  * @offs: start offset (register) to write to
301*4882a593Smuzhiyun  * @count: number of bytes to write
302*4882a593Smuzhiyun  */
asd_write_reg_string(struct asd_ha_struct * asd_ha,void * src,u32 offs,int count)303*4882a593Smuzhiyun void asd_write_reg_string(struct asd_ha_struct *asd_ha, void *src,
304*4882a593Smuzhiyun 			  u32 offs, int count)
305*4882a593Smuzhiyun {
306*4882a593Smuzhiyun 	u8 *p = src;
307*4882a593Smuzhiyun 	unsigned long flags;
308*4882a593Smuzhiyun 
309*4882a593Smuzhiyun 	spin_lock_irqsave(&asd_ha->iolock, flags);
310*4882a593Smuzhiyun 	for ( ; count > 0; count--, offs++, p++)
311*4882a593Smuzhiyun 		__asd_write_reg_byte(asd_ha, offs, *p);
312*4882a593Smuzhiyun 	spin_unlock_irqrestore(&asd_ha->iolock, flags);
313*4882a593Smuzhiyun }
314