xref: /rk3399_rockchip-uboot/drivers/net/xilinx_ll_temac.c (revision 98f705c9cefdfdba62c069821bbba10273a0a8ed)
1df482650SStephan Linz /*
2df482650SStephan Linz  * Xilinx xps_ll_temac ethernet driver for u-boot
3df482650SStephan Linz  *
4df482650SStephan Linz  * supports SDMA or FIFO access and MDIO bus communication
5df482650SStephan Linz  *
6df482650SStephan Linz  * Copyright (C) 2011 - 2012 Stephan Linz <linz@li-pro.net>
7df482650SStephan Linz  * Copyright (C) 2008 - 2011 Michal Simek <monstr@monstr.eu>
8df482650SStephan Linz  * Copyright (C) 2008 - 2011 PetaLogix
9df482650SStephan Linz  *
10df482650SStephan Linz  * Based on Yoshio Kashiwagi kashiwagi@co-nss.co.jp driver
11df482650SStephan Linz  * Copyright (C) 2008 Nissin Systems Co.,Ltd.
12df482650SStephan Linz  * March 2008 created
13df482650SStephan Linz  *
141a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
15df482650SStephan Linz  *
16df482650SStephan Linz  * [0]: http://www.xilinx.com/support/documentation
17df482650SStephan Linz  *
18df482650SStephan Linz  * [S]:	[0]/ip_documentation/xps_ll_temac.pdf
19df482650SStephan Linz  * [A]:	[0]/application_notes/xapp1041.pdf
20df482650SStephan Linz  */
21df482650SStephan Linz 
22df482650SStephan Linz #include <config.h>
23df482650SStephan Linz #include <common.h>
24df482650SStephan Linz #include <net.h>
25df482650SStephan Linz #include <netdev.h>
26df482650SStephan Linz #include <malloc.h>
27df482650SStephan Linz #include <asm/io.h>
28df482650SStephan Linz #include <miiphy.h>
29df482650SStephan Linz 
30df482650SStephan Linz #include "xilinx_ll_temac.h"
31df482650SStephan Linz #include "xilinx_ll_temac_fifo.h"
32df482650SStephan Linz #include "xilinx_ll_temac_sdma.h"
33df482650SStephan Linz #include "xilinx_ll_temac_mdio.h"
34df482650SStephan Linz 
35df482650SStephan Linz #if !defined(CONFIG_MII)
36df482650SStephan Linz # error "LL_TEMAC requires MII -- missing CONFIG_MII"
37df482650SStephan Linz #endif
38df482650SStephan Linz 
39df482650SStephan Linz #if !defined(CONFIG_PHYLIB)
40df482650SStephan Linz # error "LL_TEMAC requires PHYLIB -- missing CONFIG_PHYLIB"
41df482650SStephan Linz #endif
42df482650SStephan Linz 
43df482650SStephan Linz struct ll_temac_info {
44df482650SStephan Linz 	int			flags;
45df482650SStephan Linz 	unsigned long		base_addr;
46df482650SStephan Linz 	unsigned long		ctrl_addr;
47df482650SStephan Linz 	char			*devname;
48df482650SStephan Linz 	unsigned int		phyaddr;
49df482650SStephan Linz 	char			*mdio_busname;
50df482650SStephan Linz };
51df482650SStephan Linz 
52df482650SStephan Linz /* Ethernet interface ready status */
ll_temac_check_status(struct temac_reg * regs,u32 mask)53df482650SStephan Linz int ll_temac_check_status(struct temac_reg *regs, u32 mask)
54df482650SStephan Linz {
55df482650SStephan Linz 	unsigned timeout = 50;	/* 1usec * 50 = 50usec */
56df482650SStephan Linz 
57df482650SStephan Linz 	/*
58df482650SStephan Linz 	 * Quote from LL TEMAC documentation: The bits in the RDY
59df482650SStephan Linz 	 * register are asserted when there is no access in progress.
60df482650SStephan Linz 	 * When an access is in progress, a bit corresponding to the
61df482650SStephan Linz 	 * type of access is automatically de-asserted. The bit is
62df482650SStephan Linz 	 * automatically re-asserted when the access is complete.
63df482650SStephan Linz 	 */
64df482650SStephan Linz 	while (timeout && (!(in_be32(&regs->rdy) & mask))) {
65df482650SStephan Linz 		timeout--;
66df482650SStephan Linz 		udelay(1);
67df482650SStephan Linz 	}
68df482650SStephan Linz 
69df482650SStephan Linz 	if (!timeout) {
70df482650SStephan Linz 		printf("%s: Timeout on 0x%08x @%p\n", __func__,
71df482650SStephan Linz 				mask, &regs->rdy);
72df482650SStephan Linz 		return 1;
73df482650SStephan Linz 	}
74df482650SStephan Linz 
75df482650SStephan Linz 	return 0;
76df482650SStephan Linz }
77df482650SStephan Linz 
78df482650SStephan Linz /*
79df482650SStephan Linz  * Indirect write to ll_temac.
80df482650SStephan Linz  *
81df482650SStephan Linz  * http://www.xilinx.com/support/documentation/ip_documentation/xps_ll_temac.pdf
82df482650SStephan Linz  * page 23, second paragraph, The use of CTL0 register or CTL1 register
83df482650SStephan Linz  */
ll_temac_indirect_set(struct temac_reg * regs,u16 regn,u32 reg_data)84df482650SStephan Linz int ll_temac_indirect_set(struct temac_reg *regs, u16 regn, u32 reg_data)
85df482650SStephan Linz {
86df482650SStephan Linz 	out_be32(&regs->lsw, (reg_data & MLSW_MASK));
87df482650SStephan Linz 	out_be32(&regs->ctl, CTL_WEN | (regn & CTL_ADDR_MASK));
88df482650SStephan Linz 
89df482650SStephan Linz 	if (ll_temac_check_status(regs, RSE_CFG_WR))
90df482650SStephan Linz 		return 0;
91df482650SStephan Linz 
92df482650SStephan Linz 	return 1;
93df482650SStephan Linz }
94df482650SStephan Linz 
95df482650SStephan Linz /*
96df482650SStephan Linz  * Indirect read from ll_temac.
97df482650SStephan Linz  *
98df482650SStephan Linz  * http://www.xilinx.com/support/documentation/ip_documentation/xps_ll_temac.pdf
99df482650SStephan Linz  * page 23, second paragraph, The use of CTL0 register or CTL1 register
100df482650SStephan Linz  */
ll_temac_indirect_get(struct temac_reg * regs,u16 regn,u32 * reg_data)101df482650SStephan Linz int ll_temac_indirect_get(struct temac_reg *regs, u16 regn, u32* reg_data)
102df482650SStephan Linz {
103df482650SStephan Linz 	out_be32(&regs->ctl, (regn & CTL_ADDR_MASK));
104df482650SStephan Linz 
105df482650SStephan Linz 	if (ll_temac_check_status(regs, RSE_CFG_RR))
106df482650SStephan Linz 		return 0;
107df482650SStephan Linz 
108df482650SStephan Linz 	*reg_data = in_be32(&regs->lsw) & MLSW_MASK;
109df482650SStephan Linz 	return 1;
110df482650SStephan Linz }
111df482650SStephan Linz 
112df482650SStephan Linz /* setting sub-controller and ll_temac to proper setting */
ll_temac_setup_ctrl(struct eth_device * dev)113df482650SStephan Linz static int ll_temac_setup_ctrl(struct eth_device *dev)
114df482650SStephan Linz {
115df482650SStephan Linz 	struct ll_temac *ll_temac = dev->priv;
116df482650SStephan Linz 	struct temac_reg *regs = (struct temac_reg *)dev->iobase;
117df482650SStephan Linz 
118df482650SStephan Linz 	if (ll_temac->ctrlreset && ll_temac->ctrlreset(dev))
119df482650SStephan Linz 		return 0;
120df482650SStephan Linz 
121df482650SStephan Linz 	if (ll_temac->ctrlinit && ll_temac->ctrlinit(dev))
122df482650SStephan Linz 		return 0;
123df482650SStephan Linz 
124df482650SStephan Linz 	/* Promiscuous mode disable */
125df482650SStephan Linz 	if (!ll_temac_indirect_set(regs, TEMAC_AFM, 0))
126df482650SStephan Linz 		return 0;
127df482650SStephan Linz 
128df482650SStephan Linz 	/* Enable Receiver - RX bit */
129df482650SStephan Linz 	if (!ll_temac_indirect_set(regs, TEMAC_RCW1, RCW1_RX))
130df482650SStephan Linz 		return 0;
131df482650SStephan Linz 
132df482650SStephan Linz 	/* Enable Transmitter - TX bit */
133df482650SStephan Linz 	if (!ll_temac_indirect_set(regs, TEMAC_TC, TC_TX))
134df482650SStephan Linz 		return 0;
135df482650SStephan Linz 
136df482650SStephan Linz 	return 1;
137df482650SStephan Linz }
138df482650SStephan Linz 
139df482650SStephan Linz /*
140df482650SStephan Linz  * Configure ll_temac based on negotiated speed and duplex
141df482650SStephan Linz  * reported by PHY handling code
142df482650SStephan Linz  */
ll_temac_adjust_link(struct eth_device * dev)143df482650SStephan Linz static int ll_temac_adjust_link(struct eth_device *dev)
144df482650SStephan Linz {
145df482650SStephan Linz 	unsigned int speed, emmc_reg;
146df482650SStephan Linz 	struct temac_reg *regs = (struct temac_reg *)dev->iobase;
147df482650SStephan Linz 	struct ll_temac *ll_temac = dev->priv;
148df482650SStephan Linz 	struct phy_device *phydev = ll_temac->phydev;
149df482650SStephan Linz 
150df482650SStephan Linz 	if (!phydev->link) {
151df482650SStephan Linz 		printf("%s: No link.\n", phydev->dev->name);
152df482650SStephan Linz 		return 0;
153df482650SStephan Linz 	}
154df482650SStephan Linz 
155df482650SStephan Linz 	switch (phydev->speed) {
156df482650SStephan Linz 	case 1000:
157df482650SStephan Linz 		speed = EMMC_LSPD_1000;
158df482650SStephan Linz 		break;
159df482650SStephan Linz 	case 100:
160df482650SStephan Linz 		speed = EMMC_LSPD_100;
161df482650SStephan Linz 		break;
162df482650SStephan Linz 	case 10:
163df482650SStephan Linz 		speed = EMMC_LSPD_10;
164df482650SStephan Linz 		break;
165df482650SStephan Linz 	default:
166df482650SStephan Linz 		return 0;
167df482650SStephan Linz 	}
168df482650SStephan Linz 
169df482650SStephan Linz 	if (!ll_temac_indirect_get(regs, TEMAC_EMMC, &emmc_reg))
170df482650SStephan Linz 		return 0;
171df482650SStephan Linz 
172df482650SStephan Linz 	emmc_reg &= ~EMMC_LSPD_MASK;
173df482650SStephan Linz 	emmc_reg |= speed;
174df482650SStephan Linz 
175df482650SStephan Linz 	if (!ll_temac_indirect_set(regs, TEMAC_EMMC, emmc_reg))
176df482650SStephan Linz 		return 0;
177df482650SStephan Linz 
178df482650SStephan Linz 	printf("%s: PHY is %s with %dbase%s, %s%s\n",
179df482650SStephan Linz 			dev->name, phydev->drv->name,
180df482650SStephan Linz 			phydev->speed, (phydev->port == PORT_TP) ? "T" : "X",
181df482650SStephan Linz 			(phydev->duplex) ? "FDX" : "HDX",
182df482650SStephan Linz 			(phydev->port == PORT_OTHER) ? ", unkown mode" : "");
183df482650SStephan Linz 
184df482650SStephan Linz 	return 1;
185df482650SStephan Linz }
186df482650SStephan Linz 
187df482650SStephan Linz /* setup mac addr */
ll_temac_setup_mac_addr(struct eth_device * dev)188df482650SStephan Linz static int ll_temac_setup_mac_addr(struct eth_device *dev)
189df482650SStephan Linz {
190df482650SStephan Linz 	struct temac_reg *regs = (struct temac_reg *)dev->iobase;
191df482650SStephan Linz 	u32 val;
192df482650SStephan Linz 
193df482650SStephan Linz 	/* set up unicast MAC address filter */
194df482650SStephan Linz 	val = ((dev->enetaddr[3] << 24) | (dev->enetaddr[2] << 16) |
195df482650SStephan Linz 			(dev->enetaddr[1] << 8) | (dev->enetaddr[0]));
196df482650SStephan Linz 	val &= UAW0_UADDR_MASK;
197df482650SStephan Linz 
198df482650SStephan Linz 	if (!ll_temac_indirect_set(regs, TEMAC_UAW0, val))
199df482650SStephan Linz 		return 1;
200df482650SStephan Linz 
201df482650SStephan Linz 	val = ((dev->enetaddr[5] << 8) | dev->enetaddr[4]);
202df482650SStephan Linz 	val &= UAW1_UADDR_MASK;
203df482650SStephan Linz 
204df482650SStephan Linz 	if (!ll_temac_indirect_set(regs, TEMAC_UAW1, val))
205df482650SStephan Linz 		return 1;
206df482650SStephan Linz 
207df482650SStephan Linz 	return 0;
208df482650SStephan Linz }
209df482650SStephan Linz 
210df482650SStephan Linz /* halt device */
ll_temac_halt(struct eth_device * dev)211df482650SStephan Linz static void ll_temac_halt(struct eth_device *dev)
212df482650SStephan Linz {
213df482650SStephan Linz 	struct ll_temac *ll_temac = dev->priv;
214df482650SStephan Linz 	struct temac_reg *regs = (struct temac_reg *)dev->iobase;
215df482650SStephan Linz 
216df482650SStephan Linz 	/* Disable Receiver */
217df482650SStephan Linz 	ll_temac_indirect_set(regs, TEMAC_RCW0, 0);
218df482650SStephan Linz 
219df482650SStephan Linz 	/* Disable Transmitter */
220df482650SStephan Linz 	ll_temac_indirect_set(regs, TEMAC_TC, 0);
221df482650SStephan Linz 
222df482650SStephan Linz 	if (ll_temac->ctrlhalt)
223df482650SStephan Linz 		ll_temac->ctrlhalt(dev);
224df482650SStephan Linz 
225df482650SStephan Linz 	/* Shut down the PHY, as needed */
226df482650SStephan Linz 	phy_shutdown(ll_temac->phydev);
227df482650SStephan Linz }
228df482650SStephan Linz 
ll_temac_init(struct eth_device * dev,bd_t * bis)229df482650SStephan Linz static int ll_temac_init(struct eth_device *dev, bd_t *bis)
230df482650SStephan Linz {
231df482650SStephan Linz 	struct ll_temac *ll_temac = dev->priv;
23211af8d65STimur Tabi 	int ret;
233df482650SStephan Linz 
234527cd43dSMichal Simek 	printf("%s: Xilinx XPS LocalLink Tri-Mode Ether MAC #%d at 0x%08lx.\n",
235df482650SStephan Linz 		dev->name, dev->index, dev->iobase);
236df482650SStephan Linz 
237df482650SStephan Linz 	if (!ll_temac_setup_ctrl(dev))
238df482650SStephan Linz 		return -1;
239df482650SStephan Linz 
240df482650SStephan Linz 	/* Start up the PHY */
24111af8d65STimur Tabi 	ret = phy_startup(ll_temac->phydev);
24211af8d65STimur Tabi 	if (ret) {
24311af8d65STimur Tabi 		printf("%s: Could not initialize PHY %s\n",
24411af8d65STimur Tabi 		       dev->name, ll_temac->phydev->dev->name);
24511af8d65STimur Tabi 		return ret;
24611af8d65STimur Tabi 	}
247df482650SStephan Linz 
248df482650SStephan Linz 	if (!ll_temac_adjust_link(dev)) {
249df482650SStephan Linz 		ll_temac_halt(dev);
250df482650SStephan Linz 		return -1;
251df482650SStephan Linz 	}
252df482650SStephan Linz 
253df482650SStephan Linz 	/* If there's no link, fail */
254df482650SStephan Linz 	return ll_temac->phydev->link ? 0 : -1;
255df482650SStephan Linz }
256df482650SStephan Linz 
257df482650SStephan Linz /*
258df482650SStephan Linz  * Discover which PHY is attached to the device, and configure it
259df482650SStephan Linz  * properly.  If the PHY is not recognized, then return 0
260df482650SStephan Linz  * (failure).  Otherwise, return 1
261df482650SStephan Linz  */
ll_temac_phy_init(struct eth_device * dev)262df482650SStephan Linz static int ll_temac_phy_init(struct eth_device *dev)
263df482650SStephan Linz {
264df482650SStephan Linz 	struct ll_temac *ll_temac = dev->priv;
265df482650SStephan Linz 	struct phy_device *phydev;
266df482650SStephan Linz 	unsigned int supported = PHY_GBIT_FEATURES;
267df482650SStephan Linz 
268df482650SStephan Linz 	/* interface - look at driver/net/tsec.c */
269df482650SStephan Linz 	phydev = phy_connect(ll_temac->bus, ll_temac->phyaddr,
270df482650SStephan Linz 			dev, PHY_INTERFACE_MODE_NONE);
271df482650SStephan Linz 
272df482650SStephan Linz 	phydev->supported &= supported;
273df482650SStephan Linz 	phydev->advertising = phydev->supported;
274df482650SStephan Linz 
275df482650SStephan Linz 	ll_temac->phydev = phydev;
276df482650SStephan Linz 
277df482650SStephan Linz 	phy_config(phydev);
278df482650SStephan Linz 
279df482650SStephan Linz 	return 1;
280df482650SStephan Linz }
281df482650SStephan Linz 
282df482650SStephan Linz /*
283df482650SStephan Linz  * Initialize a single ll_temac devices
284df482650SStephan Linz  *
285df482650SStephan Linz  * Returns the result of ll_temac phy interface that were initialized
286df482650SStephan Linz  */
xilinx_ll_temac_initialize(bd_t * bis,struct ll_temac_info * devinf)287df482650SStephan Linz int xilinx_ll_temac_initialize(bd_t *bis, struct ll_temac_info *devinf)
288df482650SStephan Linz {
289df482650SStephan Linz 	struct eth_device *dev;
290df482650SStephan Linz 	struct ll_temac *ll_temac;
291df482650SStephan Linz 
292df482650SStephan Linz 	dev = calloc(1, sizeof(*dev));
293df482650SStephan Linz 	if (dev == NULL)
294df482650SStephan Linz 		return 0;
295df482650SStephan Linz 
296df482650SStephan Linz 	ll_temac = calloc(1, sizeof(struct ll_temac));
297df482650SStephan Linz 	if (ll_temac == NULL) {
298df482650SStephan Linz 		free(dev);
299df482650SStephan Linz 		return 0;
300df482650SStephan Linz 	}
301df482650SStephan Linz 
302df482650SStephan Linz 	/* use given name or generate its own unique name */
303df482650SStephan Linz 	if (devinf->devname) {
30434921d04SStephan Linz 		strncpy(dev->name, devinf->devname, sizeof(dev->name));
305df482650SStephan Linz 	} else {
306*21909bafSRicardo Ribalda Delgado 		snprintf(dev->name, sizeof(dev->name), "ll_tem.%lx",
307*21909bafSRicardo Ribalda Delgado 			 devinf->base_addr);
308df482650SStephan Linz 		devinf->devname = dev->name;
309df482650SStephan Linz 	}
310df482650SStephan Linz 
311df482650SStephan Linz 	dev->iobase = devinf->base_addr;
312df482650SStephan Linz 
313df482650SStephan Linz 	dev->priv = ll_temac;
314df482650SStephan Linz 	dev->init = ll_temac_init;
315df482650SStephan Linz 	dev->halt = ll_temac_halt;
316df482650SStephan Linz 	dev->write_hwaddr = ll_temac_setup_mac_addr;
317df482650SStephan Linz 
318df482650SStephan Linz 	ll_temac->ctrladdr = devinf->ctrl_addr;
319df482650SStephan Linz 	if (devinf->flags & XILINX_LL_TEMAC_M_SDMA_PLB) {
320df482650SStephan Linz 		ll_temac_collect_xlplb_sdma_reg_addr(dev);
321df482650SStephan Linz 		ll_temac->in32 = ll_temac_xlplb_in32;
322df482650SStephan Linz 		ll_temac->out32 = ll_temac_xlplb_out32;
323df482650SStephan Linz 		ll_temac->ctrlinit = ll_temac_init_sdma;
324df482650SStephan Linz 		ll_temac->ctrlhalt = ll_temac_halt_sdma;
325df482650SStephan Linz 		ll_temac->ctrlreset = ll_temac_reset_sdma;
326df482650SStephan Linz 		dev->recv = ll_temac_recv_sdma;
327df482650SStephan Linz 		dev->send = ll_temac_send_sdma;
328df482650SStephan Linz 	} else {
329df482650SStephan Linz 		ll_temac->in32 = NULL;
330df482650SStephan Linz 		ll_temac->out32 = NULL;
331df482650SStephan Linz 		ll_temac->ctrlinit = NULL;
332df482650SStephan Linz 		ll_temac->ctrlhalt = NULL;
333df482650SStephan Linz 		ll_temac->ctrlreset = ll_temac_reset_fifo;
334df482650SStephan Linz 		dev->recv = ll_temac_recv_fifo;
335df482650SStephan Linz 		dev->send = ll_temac_send_fifo;
336df482650SStephan Linz 	}
337df482650SStephan Linz 
338df482650SStephan Linz 	/* Link to specified MDIO bus */
339df482650SStephan Linz 	strncpy(ll_temac->mdio_busname, devinf->mdio_busname, MDIO_NAME_LEN);
340df482650SStephan Linz 	ll_temac->bus = miiphy_get_dev_by_name(ll_temac->mdio_busname);
341df482650SStephan Linz 
342df482650SStephan Linz 	/* Looking for a valid PHY address if it is not yet set */
343df482650SStephan Linz 	if (devinf->phyaddr == -1)
344df482650SStephan Linz 		ll_temac->phyaddr = ll_temac_phy_addr(ll_temac->bus);
345df482650SStephan Linz 	else
346df482650SStephan Linz 		ll_temac->phyaddr = devinf->phyaddr;
347df482650SStephan Linz 
348df482650SStephan Linz 	eth_register(dev);
349df482650SStephan Linz 
350df482650SStephan Linz 	/* Try to initialize PHY here, and return */
351df482650SStephan Linz 	return ll_temac_phy_init(dev);
352df482650SStephan Linz }
353df482650SStephan Linz 
354df482650SStephan Linz /*
355df482650SStephan Linz  * Initialize a single ll_temac device with its mdio bus behind ll_temac
356df482650SStephan Linz  *
357df482650SStephan Linz  * Returns 1 if the ll_temac device and the mdio bus were initialized
358df482650SStephan Linz  * otherwise returns 0
359df482650SStephan Linz  */
xilinx_ll_temac_eth_init(bd_t * bis,unsigned long base_addr,int flags,unsigned long ctrl_addr)360df482650SStephan Linz int xilinx_ll_temac_eth_init(bd_t *bis, unsigned long base_addr, int flags,
361df482650SStephan Linz 							unsigned long ctrl_addr)
362df482650SStephan Linz {
363df482650SStephan Linz 	struct ll_temac_info devinf;
364df482650SStephan Linz 	struct ll_temac_mdio_info mdioinf;
365df482650SStephan Linz 	int ret;
366df482650SStephan Linz 
367df482650SStephan Linz 	/* prepare the internal driver informations */
368df482650SStephan Linz 	devinf.flags = flags;
369df482650SStephan Linz 	devinf.base_addr = base_addr;
370df482650SStephan Linz 	devinf.ctrl_addr = ctrl_addr;
371df482650SStephan Linz 	devinf.devname = NULL;
372df482650SStephan Linz 	devinf.phyaddr = -1;
373df482650SStephan Linz 
374df482650SStephan Linz 	mdioinf.name = devinf.mdio_busname = NULL;
375df482650SStephan Linz 	mdioinf.regs = (struct temac_reg *)devinf.base_addr;
376df482650SStephan Linz 
377df482650SStephan Linz 	ret = xilinx_ll_temac_mdio_initialize(bis, &mdioinf);
378df482650SStephan Linz 	if (ret >= 0) {
379df482650SStephan Linz 
380df482650SStephan Linz 		/*
381df482650SStephan Linz 		 * If there was no MDIO bus name then take over the
382df482650SStephan Linz 		 * new automaticaly generated by the MDIO init code.
383df482650SStephan Linz 		 */
384df482650SStephan Linz 		if (mdioinf.name != devinf.mdio_busname)
385df482650SStephan Linz 			devinf.mdio_busname = mdioinf.name;
386df482650SStephan Linz 
387df482650SStephan Linz 		ret = xilinx_ll_temac_initialize(bis, &devinf);
388df482650SStephan Linz 		if (ret > 0)
389df482650SStephan Linz 			return 1;
390df482650SStephan Linz 
391df482650SStephan Linz 	}
392df482650SStephan Linz 
393df482650SStephan Linz 	return 0;
394df482650SStephan Linz }
395