asix_common.c 14.8 KB
Newer Older
1 2
/*
 * ASIX AX8817X based USB 2.0 Ethernet Devices
3
 * Copyright (C) 2003-2006 David Hollis <dhollis@davehollis.com>
4
 * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net>
5
 * Copyright (C) 2006 James Painter <jamie.painter@iname.com>
6 7 8 9 10 11 12 13 14 15 16 17 18
 * Copyright (c) 2002-2003 TiVo Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
19
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
20 21
 */

C
Christian Riesch 已提交
22 23 24 25
#include "asix.h"

int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
		  u16 size, void *data)
26
{
27 28 29 30 31 32 33 34
	int ret;
	ret = usbnet_read_cmd(dev, cmd,
			       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
			       value, index, data, size);

	if (ret != size && ret >= 0)
		return -EINVAL;
	return ret;
35 36
}

C
Christian Riesch 已提交
37 38
int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
		   u16 size, void *data)
39
{
40 41 42
	return usbnet_write_cmd(dev, cmd,
				USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
				value, index, data, size);
43 44
}

C
Christian Riesch 已提交
45 46
void asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
			  u16 size, void *data)
47
{
48 49 50
	usbnet_write_cmd_async(dev, cmd,
			       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
			       value, index, data, size);
51 52
}

53 54
int asix_rx_fixup_internal(struct usbnet *dev, struct sk_buff *skb,
			   struct asix_rx_fixup_info *rx)
55
{
56
	int offset = 0;
57
	u16 size;
58

59
	while (offset + sizeof(u16) <= skb->len) {
60
		u16 copy_length;
61
		unsigned char *data;
62

63
		if (!rx->remaining) {
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
			if ((skb->len - offset == sizeof(u16)) ||
			    rx->split_head) {
				if(!rx->split_head) {
					rx->header = get_unaligned_le16(
							skb->data + offset);
					rx->split_head = true;
					offset += sizeof(u16);
					break;
				} else {
					rx->header |= (get_unaligned_le16(
							skb->data + offset)
							<< 16);
					rx->split_head = false;
					offset += sizeof(u16);
				}
			} else {
				rx->header = get_unaligned_le32(skb->data +
								offset);
				offset += sizeof(u32);
			}
84

85 86 87
			/* take frame length from Data header 32-bit word */
			size = (u16)(rx->header & 0x7ff);
			if (size != ((~rx->header >> 16) & 0x7ff)) {
88 89 90 91
				netdev_err(dev->net, "asix_rx_fixup() Bad Header Length 0x%x, offset %d\n",
					   rx->header, offset);
				return 0;
			}
92
			rx->ax_skb = netdev_alloc_skb_ip_align(dev->net, size);
93 94
			if (!rx->ax_skb)
				return 0;
95
			rx->remaining = size;
96 97
		}

98
		if (rx->remaining > dev->net->mtu + ETH_HLEN + VLAN_HLEN) {
99
			netdev_err(dev->net, "asix_rx_fixup() Bad RX Length %d\n",
100
				   rx->remaining);
101
			kfree_skb(rx->ax_skb);
102
			rx->ax_skb = NULL;
103
			rx->remaining = 0;
104 105 106
			return 0;
		}

107 108 109 110 111 112
		if (rx->remaining > skb->len - offset) {
			copy_length = skb->len - offset;
			rx->remaining -= copy_length;
		} else {
			copy_length = rx->remaining;
			rx->remaining = 0;
113
		}
114

115 116 117
		data = skb_put(rx->ax_skb, copy_length);
		memcpy(data, skb->data + offset, copy_length);
		if (!rx->remaining)
118 119
			usbnet_skb_return(dev, rx->ax_skb);

120
		offset += (copy_length + 1) & 0xfffe;
121 122
	}

123
	if (skb->len != offset) {
124 125
		netdev_err(dev->net, "asix_rx_fixup() Bad SKB Length %d, %d\n",
			   skb->len, offset);
126 127
		return 0;
	}
128

129 130 131
	return 1;
}

132 133 134 135 136 137 138 139
int asix_rx_fixup_common(struct usbnet *dev, struct sk_buff *skb)
{
	struct asix_common_private *dp = dev->driver_priv;
	struct asix_rx_fixup_info *rx = &dp->rx_fixup_info;

	return asix_rx_fixup_internal(dev, skb, rx);
}

C
Christian Riesch 已提交
140 141
struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
			      gfp_t flags)
142 143 144 145 146 147 148
{
	int padlen;
	int headroom = skb_headroom(skb);
	int tailroom = skb_tailroom(skb);
	u32 packet_len;
	u32 padbytes = 0xffff0000;

149
	padlen = ((skb->len + 4) & (dev->maxpacket - 1)) ? 0 : 4;
150

E
Eric Dumazet 已提交
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
	/* We need to push 4 bytes in front of frame (packet_len)
	 * and maybe add 4 bytes after the end (if padlen is 4)
	 *
	 * Avoid skb_copy_expand() expensive call, using following rules :
	 * - We are allowed to push 4 bytes in headroom if skb_header_cloned()
	 *   is false (and if we have 4 bytes of headroom)
	 * - We are allowed to put 4 bytes at tail if skb_cloned()
	 *   is false (and if we have 4 bytes of tailroom)
	 *
	 * TCP packets for example are cloned, but skb_header_release()
	 * was called in tcp stack, allowing us to use headroom for our needs.
	 */
	if (!skb_header_cloned(skb) &&
	    !(padlen && skb_cloned(skb)) &&
	    headroom + tailroom >= 4 + padlen) {
		/* following should not happen, but better be safe */
		if (headroom < 4 ||
		    tailroom < padlen) {
169
			skb->data = memmove(skb->head + 4, skb->data, skb->len);
170
			skb_set_tail_pointer(skb, skb->len);
171 172 173
		}
	} else {
		struct sk_buff *skb2;
E
Eric Dumazet 已提交
174

175 176 177 178 179 180 181
		skb2 = skb_copy_expand(skb, 4, padlen, flags);
		dev_kfree_skb_any(skb);
		skb = skb2;
		if (!skb)
			return NULL;
	}

E
Eric Dumazet 已提交
182
	packet_len = ((skb->len ^ 0x0000ffff) << 16) + skb->len;
183
	skb_push(skb, 4);
184
	cpu_to_le32s(&packet_len);
185
	skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len));
186

187
	if (padlen) {
188
		cpu_to_le32s(&padbytes);
189
		memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes));
190 191
		skb_put(skb, sizeof(padbytes));
	}
192

193
	usbnet_set_skb_tx_stats(skb, 1, 0);
194 195 196
	return skb;
}

C
Christian Riesch 已提交
197
int asix_set_sw_mii(struct usbnet *dev)
198 199 200 201
{
	int ret;
	ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL);
	if (ret < 0)
202
		netdev_err(dev->net, "Failed to enable software MII access\n");
203 204 205
	return ret;
}

C
Christian Riesch 已提交
206
int asix_set_hw_mii(struct usbnet *dev)
207 208 209 210
{
	int ret;
	ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL);
	if (ret < 0)
211
		netdev_err(dev->net, "Failed to enable hardware MII access\n");
212 213 214
	return ret;
}

215
int asix_read_phy_addr(struct usbnet *dev, int internal)
216
{
217
	int offset = (internal ? 1 : 0);
A
Al Viro 已提交
218 219
	u8 buf[2];
	int ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID, 0, 0, 2, buf);
220

221
	netdev_dbg(dev->net, "asix_get_phy_addr()\n");
222

A
Al Viro 已提交
223
	if (ret < 0) {
224
		netdev_err(dev->net, "Error reading PHYID register: %02x\n", ret);
A
Al Viro 已提交
225
		goto out;
226
	}
227 228
	netdev_dbg(dev->net, "asix_get_phy_addr() returning 0x%04x\n",
		   *((__le16 *)buf));
229
	ret = buf[offset];
A
Al Viro 已提交
230 231

out:
232 233 234
	return ret;
}

235 236 237 238 239 240 241
int asix_get_phy_addr(struct usbnet *dev)
{
	/* return the address of the internal phy */
	return asix_read_phy_addr(dev, 1);
}


C
Christian Riesch 已提交
242
int asix_sw_reset(struct usbnet *dev, u8 flags)
243 244 245 246 247
{
	int ret;

        ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL);
	if (ret < 0)
248
		netdev_err(dev->net, "Failed to send software reset: %02x\n", ret);
249 250 251

	return ret;
}
252

C
Christian Riesch 已提交
253
u16 asix_read_rx_ctl(struct usbnet *dev)
254
{
A
Al Viro 已提交
255 256
	__le16 v;
	int ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL, 0, 0, 2, &v);
257

A
Al Viro 已提交
258
	if (ret < 0) {
259
		netdev_err(dev->net, "Error reading RX_CTL register: %02x\n", ret);
A
Al Viro 已提交
260
		goto out;
261
	}
A
Al Viro 已提交
262 263
	ret = le16_to_cpu(v);
out:
264 265 266
	return ret;
}

C
Christian Riesch 已提交
267
int asix_write_rx_ctl(struct usbnet *dev, u16 mode)
268 269 270
{
	int ret;

271
	netdev_dbg(dev->net, "asix_write_rx_ctl() - mode = 0x%04x\n", mode);
272 273
	ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL);
	if (ret < 0)
274 275
		netdev_err(dev->net, "Failed to write RX_CTL mode to 0x%04x: %02x\n",
			   mode, ret);
276 277 278 279

	return ret;
}

C
Christian Riesch 已提交
280
u16 asix_read_medium_status(struct usbnet *dev)
281
{
A
Al Viro 已提交
282 283
	__le16 v;
	int ret = asix_read_cmd(dev, AX_CMD_READ_MEDIUM_STATUS, 0, 0, 2, &v);
284

A
Al Viro 已提交
285
	if (ret < 0) {
286 287
		netdev_err(dev->net, "Error reading Medium Status register: %02x\n",
			   ret);
288
		return ret;	/* TODO: callers not checking for error ret */
289
	}
290 291 292

	return le16_to_cpu(v);

293 294
}

C
Christian Riesch 已提交
295
int asix_write_medium_mode(struct usbnet *dev, u16 mode)
296
{
297
	int ret;
298

299
	netdev_dbg(dev->net, "asix_write_medium_mode() - mode = 0x%04x\n", mode);
300 301
	ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL);
	if (ret < 0)
302 303
		netdev_err(dev->net, "Failed to write Medium Mode mode to 0x%04x: %02x\n",
			   mode, ret);
304

305 306
	return ret;
}
307

C
Christian Riesch 已提交
308
int asix_write_gpio(struct usbnet *dev, u16 value, int sleep)
309 310
{
	int ret;
311

312
	netdev_dbg(dev->net, "asix_write_gpio() - value = 0x%04x\n", value);
313 314
	ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL);
	if (ret < 0)
315 316
		netdev_err(dev->net, "Failed to write GPIO value 0x%04x: %02x\n",
			   value, ret);
317

318 319 320 321
	if (sleep)
		msleep(sleep);

	return ret;
322 323
}

324 325 326
/*
 * AX88772 & AX88178 have a 16-bit RX_CTL value
 */
C
Christian Riesch 已提交
327
void asix_set_multicast(struct net_device *net)
328 329
{
	struct usbnet *dev = netdev_priv(net);
330
	struct asix_data *data = (struct asix_data *)&dev->data;
331
	u16 rx_ctl = AX_DEFAULT_RX_CTL;
332 333

	if (net->flags & IFF_PROMISC) {
334
		rx_ctl |= AX_RX_CTL_PRO;
335
	} else if (net->flags & IFF_ALLMULTI ||
336
		   netdev_mc_count(net) > AX_MAX_MCAST) {
337
		rx_ctl |= AX_RX_CTL_AMALL;
338
	} else if (netdev_mc_empty(net)) {
339 340 341 342 343 344
		/* just broadcast and directed */
	} else {
		/* We use the 20 byte dev->data
		 * for our 8 byte filter buffer
		 * to avoid allocating memory that
		 * is tricky to free later */
345
		struct netdev_hw_addr *ha;
346 347 348 349 350
		u32 crc_bits;

		memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE);

		/* Build the multicast hash filter. */
351 352
		netdev_for_each_mc_addr(ha, net) {
			crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26;
353 354 355 356
			data->multi_filter[crc_bits >> 3] |=
			    1 << (crc_bits & 7);
		}

357
		asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0,
358 359
				   AX_MCAST_FILTER_SIZE, data->multi_filter);

360
		rx_ctl |= AX_RX_CTL_AM;
361 362
	}

363
	asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL);
364 365
}

C
Christian Riesch 已提交
366
int asix_mdio_read(struct net_device *netdev, int phy_id, int loc)
367 368
{
	struct usbnet *dev = netdev_priv(netdev);
A
Al Viro 已提交
369
	__le16 res;
370

371
	mutex_lock(&dev->phy_mutex);
372 373
	asix_set_sw_mii(dev);
	asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id,
A
Al Viro 已提交
374
				(__u16)loc, 2, &res);
375
	asix_set_hw_mii(dev);
376
	mutex_unlock(&dev->phy_mutex);
377

378 379
	netdev_dbg(dev->net, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
		   phy_id, loc, le16_to_cpu(res));
380

A
Al Viro 已提交
381
	return le16_to_cpu(res);
382 383
}

C
Christian Riesch 已提交
384
void asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
385 386
{
	struct usbnet *dev = netdev_priv(netdev);
A
Al Viro 已提交
387
	__le16 res = cpu_to_le16(val);
388

389 390
	netdev_dbg(dev->net, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
		   phy_id, loc, val);
391
	mutex_lock(&dev->phy_mutex);
392
	asix_set_sw_mii(dev);
A
Al Viro 已提交
393
	asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, &res);
394
	asix_set_hw_mii(dev);
395
	mutex_unlock(&dev->phy_mutex);
396 397
}

C
Christian Riesch 已提交
398
void asix_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
399 400 401 402
{
	struct usbnet *dev = netdev_priv(net);
	u8 opt;

403
	if (asix_read_cmd(dev, AX_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) {
404 405 406 407 408 409
		wolinfo->supported = 0;
		wolinfo->wolopts = 0;
		return;
	}
	wolinfo->supported = WAKE_PHY | WAKE_MAGIC;
	wolinfo->wolopts = 0;
410 411 412 413
	if (opt & AX_MONITOR_LINK)
		wolinfo->wolopts |= WAKE_PHY;
	if (opt & AX_MONITOR_MAGIC)
		wolinfo->wolopts |= WAKE_MAGIC;
414 415
}

C
Christian Riesch 已提交
416
int asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
417 418 419 420 421 422 423 424 425
{
	struct usbnet *dev = netdev_priv(net);
	u8 opt = 0;

	if (wolinfo->wolopts & WAKE_PHY)
		opt |= AX_MONITOR_LINK;
	if (wolinfo->wolopts & WAKE_MAGIC)
		opt |= AX_MONITOR_MAGIC;

426
	if (asix_write_cmd(dev, AX_CMD_WRITE_MONITOR_MODE,
A
Al Viro 已提交
427
			      opt, 0, 0, NULL) < 0)
428 429 430 431 432
		return -EINVAL;

	return 0;
}

C
Christian Riesch 已提交
433
int asix_get_eeprom_len(struct net_device *net)
434
{
435
	return AX_EEPROM_LEN;
436 437
}

C
Christian Riesch 已提交
438 439
int asix_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom,
		    u8 *data)
440 441
{
	struct usbnet *dev = netdev_priv(net);
442 443
	u16 *eeprom_buff;
	int first_word, last_word;
444 445
	int i;

446
	if (eeprom->len == 0)
447 448 449 450
		return -EINVAL;

	eeprom->magic = AX_EEPROM_MAGIC;

451 452 453 454 455 456 457 458
	first_word = eeprom->offset >> 1;
	last_word = (eeprom->offset + eeprom->len - 1) >> 1;

	eeprom_buff = kmalloc(sizeof(u16) * (last_word - first_word + 1),
			      GFP_KERNEL);
	if (!eeprom_buff)
		return -ENOMEM;

459
	/* ax8817x returns 2 bytes from eeprom on read */
460 461 462 463 464 465
	for (i = first_word; i <= last_word; i++) {
		if (asix_read_cmd(dev, AX_CMD_READ_EEPROM, i, 0, 2,
				  &(eeprom_buff[i - first_word])) < 0) {
			kfree(eeprom_buff);
			return -EIO;
		}
466
	}
467 468 469

	memcpy(data, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len);
	kfree(eeprom_buff);
470 471 472
	return 0;
}

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 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553
int asix_set_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom,
		    u8 *data)
{
	struct usbnet *dev = netdev_priv(net);
	u16 *eeprom_buff;
	int first_word, last_word;
	int i;
	int ret;

	netdev_dbg(net, "write EEPROM len %d, offset %d, magic 0x%x\n",
		   eeprom->len, eeprom->offset, eeprom->magic);

	if (eeprom->len == 0)
		return -EINVAL;

	if (eeprom->magic != AX_EEPROM_MAGIC)
		return -EINVAL;

	first_word = eeprom->offset >> 1;
	last_word = (eeprom->offset + eeprom->len - 1) >> 1;

	eeprom_buff = kmalloc(sizeof(u16) * (last_word - first_word + 1),
			      GFP_KERNEL);
	if (!eeprom_buff)
		return -ENOMEM;

	/* align data to 16 bit boundaries, read the missing data from
	   the EEPROM */
	if (eeprom->offset & 1) {
		ret = asix_read_cmd(dev, AX_CMD_READ_EEPROM, first_word, 0, 2,
				    &(eeprom_buff[0]));
		if (ret < 0) {
			netdev_err(net, "Failed to read EEPROM at offset 0x%02x.\n", first_word);
			goto free;
		}
	}

	if ((eeprom->offset + eeprom->len) & 1) {
		ret = asix_read_cmd(dev, AX_CMD_READ_EEPROM, last_word, 0, 2,
				    &(eeprom_buff[last_word - first_word]));
		if (ret < 0) {
			netdev_err(net, "Failed to read EEPROM at offset 0x%02x.\n", last_word);
			goto free;
		}
	}

	memcpy((u8 *)eeprom_buff + (eeprom->offset & 1), data, eeprom->len);

	/* write data to EEPROM */
	ret = asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0x0000, 0, 0, NULL);
	if (ret < 0) {
		netdev_err(net, "Failed to enable EEPROM write\n");
		goto free;
	}
	msleep(20);

	for (i = first_word; i <= last_word; i++) {
		netdev_dbg(net, "write to EEPROM at offset 0x%02x, data 0x%04x\n",
			   i, eeprom_buff[i - first_word]);
		ret = asix_write_cmd(dev, AX_CMD_WRITE_EEPROM, i,
				     eeprom_buff[i - first_word], 0, NULL);
		if (ret < 0) {
			netdev_err(net, "Failed to write EEPROM at offset 0x%02x.\n",
				   i);
			goto free;
		}
		msleep(20);
	}

	ret = asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0x0000, 0, 0, NULL);
	if (ret < 0) {
		netdev_err(net, "Failed to disable EEPROM write\n");
		goto free;
	}

	ret = 0;
free:
	kfree(eeprom_buff);
	return ret;
}

C
Christian Riesch 已提交
554
void asix_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
555 556 557
{
	/* Inherit standard device info */
	usbnet_get_drvinfo(net, info);
558 559
	strlcpy(info->driver, DRIVER_NAME, sizeof(info->driver));
	strlcpy(info->version, DRIVER_VERSION, sizeof(info->version));
560
	info->eedump_len = AX_EEPROM_LEN;
561 562
}

C
Christian Riesch 已提交
563
int asix_set_mac_address(struct net_device *net, void *p)
564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585
{
	struct usbnet *dev = netdev_priv(net);
	struct asix_data *data = (struct asix_data *)&dev->data;
	struct sockaddr *addr = p;

	if (netif_running(net))
		return -EBUSY;
	if (!is_valid_ether_addr(addr->sa_data))
		return -EADDRNOTAVAIL;

	memcpy(net->dev_addr, addr->sa_data, ETH_ALEN);

	/* We use the 20 byte dev->data
	 * for our 6 byte mac buffer
	 * to avoid allocating memory that
	 * is tricky to free later */
	memcpy(data->mac_addr, addr->sa_data, ETH_ALEN);
	asix_write_cmd_async(dev, AX_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN,
							data->mac_addr);

	return 0;
}