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