FILE
sr9700.c
File preview with syntax highlighting.
linux-6.19.14/drivers/net/usb/sr9700.c
1/* 2 * CoreChip-sz SR9700 one chip USB 1.1 Ethernet Devices 3 * 4 * Author : Liu Junliang <liujunliang_ljl@163.com> 5 * 6 * Based on dm9601.c 7 * 8 * This file is licensed under the terms of the GNU General Public License 9 * version 2. This program is licensed "as is" without any warranty of any 10 * kind, whether express or implied. 11 */ 12 13#include <linux/module.h> 14#include <linux/sched.h> 15#include <linux/stddef.h> 16#include <linux/netdevice.h> 17#include <linux/etherdevice.h> 18#include <linux/ethtool.h> 19#include <linux/mii.h> 20#include <linux/usb.h> 21#include <linux/usb/usbnet.h> 22 23#include "sr9700.h" 24 25static int sr_read(struct usbnet *dev, u8 reg, u16 length, void *data) 26{ 27 int err; 28 29 err = usbnet_read_cmd(dev, SR_RD_REGS, SR_REQ_RD_REG, 0, reg, data, 30 length); 31 if ((err != length) && (err >= 0)) 32 err = -EINVAL; 33 return err; 34} 35 36static int sr_write(struct usbnet *dev, u8 reg, u16 length, void *data) 37{ 38 int err; 39 40 err = usbnet_write_cmd(dev, SR_WR_REGS, SR_REQ_WR_REG, 0, reg, data, 41 length); 42 if ((err >= 0) && (err < length)) 43 err = -EINVAL; 44 return err; 45} 46 47static int sr_read_reg(struct usbnet *dev, u8 reg, u8 *value) 48{ 49 return sr_read(dev, reg, 1, value); 50} 51 52static int sr_write_reg(struct usbnet *dev, u8 reg, u8 value) 53{ 54 return usbnet_write_cmd(dev, SR_WR_REG, SR_REQ_WR_REG, 55 value, reg, NULL, 0); 56} 57 58static void sr_write_async(struct usbnet *dev, u8 reg, u16 length, 59 const void *data) 60{ 61 usbnet_write_cmd_async(dev, SR_WR_REGS, SR_REQ_WR_REG, 62 0, reg, data, length); 63} 64 65static void sr_write_reg_async(struct usbnet *dev, u8 reg, u8 value) 66{ 67 usbnet_write_cmd_async(dev, SR_WR_REG, SR_REQ_WR_REG, 68 value, reg, NULL, 0); 69} 70 71static int wait_phy_eeprom_ready(struct usbnet *dev, int phy) 72{ 73 int i; 74 75 for (i = 0; i < SR_SHARE_TIMEOUT; i++) { 76 u8 tmp = 0; 77 int ret; 78 79 udelay(1); 80 ret = sr_read_reg(dev, SR_EPCR, &tmp); 81 if (ret < 0) 82 return ret; 83 84 /* ready */ 85 if (!(tmp & EPCR_ERRE)) 86 return 0; 87 } 88 89 netdev_err(dev->net, "%s write timed out!\n", phy ? "phy" : "eeprom"); 90 91 return -EIO; 92} 93 94static int sr_share_read_word(struct usbnet *dev, int phy, u8 reg, 95 __le16 *value) 96{ 97 int ret; 98 99 mutex_lock(&dev->phy_mutex); 100 101 sr_write_reg(dev, SR_EPAR, phy ? (reg | EPAR_PHY_ADR) : reg); 102 sr_write_reg(dev, SR_EPCR, phy ? (EPCR_EPOS | EPCR_ERPRR) : EPCR_ERPRR); 103 104 ret = wait_phy_eeprom_ready(dev, phy); 105 if (ret < 0) 106 goto out_unlock; 107 108 sr_write_reg(dev, SR_EPCR, 0x0); 109 ret = sr_read(dev, SR_EPDR, 2, value); 110 111 netdev_dbg(dev->net, "read shared %d 0x%02x returned 0x%04x, %d\n", 112 phy, reg, *value, ret); 113 114out_unlock: 115 mutex_unlock(&dev->phy_mutex); 116 return ret; 117} 118 119static int sr_share_write_word(struct usbnet *dev, int phy, u8 reg, 120 __le16 value) 121{ 122 int ret; 123 124 mutex_lock(&dev->phy_mutex); 125 126 ret = sr_write(dev, SR_EPDR, 2, &value); 127 if (ret < 0) 128 goto out_unlock; 129 130 sr_write_reg(dev, SR_EPAR, phy ? (reg | EPAR_PHY_ADR) : reg); 131 sr_write_reg(dev, SR_EPCR, phy ? (EPCR_WEP | EPCR_EPOS | EPCR_ERPRW) : 132 (EPCR_WEP | EPCR_ERPRW)); 133 134 ret = wait_phy_eeprom_ready(dev, phy); 135 if (ret < 0) 136 goto out_unlock; 137 138 sr_write_reg(dev, SR_EPCR, 0x0); 139 140out_unlock: 141 mutex_unlock(&dev->phy_mutex); 142 return ret; 143} 144 145static int sr_read_eeprom_word(struct usbnet *dev, u8 offset, void *value) 146{ 147 return sr_share_read_word(dev, 0, offset, value); 148} 149 150static int sr9700_get_eeprom_len(struct net_device *netdev) 151{ 152 return SR_EEPROM_LEN; 153} 154 155static int sr9700_get_eeprom(struct net_device *netdev, 156 struct ethtool_eeprom *eeprom, u8 *data) 157{ 158 struct usbnet *dev = netdev_priv(netdev); 159 __le16 *buf = (__le16 *)data; 160 int ret = 0; 161 int i; 162 163 /* access is 16bit */ 164 if ((eeprom->offset & 0x01) || (eeprom->len & 0x01)) 165 return -EINVAL; 166 167 for (i = 0; i < eeprom->len / 2; i++) { 168 ret = sr_read_eeprom_word(dev, eeprom->offset / 2 + i, buf + i); 169 if (ret < 0) 170 break; 171 } 172 173 return ret; 174} 175 176static int sr_mdio_read(struct net_device *netdev, int phy_id, int loc) 177{ 178 struct usbnet *dev = netdev_priv(netdev); 179 int err, res; 180 __le16 word; 181 int rc = 0; 182 183 if (phy_id) { 184 netdev_dbg(netdev, "Only internal phy supported\n"); 185 return 0; 186 } 187 188 /* Access NSR_LINKST bit for link status instead of MII_BMSR */ 189 if (loc == MII_BMSR) { 190 u8 value; 191 192 err = sr_read_reg(dev, SR_NSR, &value); 193 if (err < 0) 194 return err; 195 196 if (value & NSR_LINKST) 197 rc = 1; 198 } 199 err = sr_share_read_word(dev, 1, loc, &word); 200 if (err < 0) 201 return err; 202 203 if (rc == 1) 204 res = le16_to_cpu(word) | BMSR_LSTATUS; 205 else 206 res = le16_to_cpu(word) & ~BMSR_LSTATUS; 207 208 netdev_dbg(netdev, "sr_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n", 209 phy_id, loc, res); 210 211 return res; 212} 213 214static void sr_mdio_write(struct net_device *netdev, int phy_id, int loc, 215 int val) 216{ 217 struct usbnet *dev = netdev_priv(netdev); 218 __le16 res = cpu_to_le16(val); 219 220 if (phy_id) { 221 netdev_dbg(netdev, "Only internal phy supported\n"); 222 return; 223 } 224 225 netdev_dbg(netdev, "sr_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n", 226 phy_id, loc, val); 227 228 sr_share_write_word(dev, 1, loc, res); 229} 230 231static u32 sr9700_get_link(struct net_device *netdev) 232{ 233 struct usbnet *dev = netdev_priv(netdev); 234 u8 value = 0; 235 int rc = 0; 236 237 /* Get the Link Status directly */ 238 sr_read_reg(dev, SR_NSR, &value); 239 if (value & NSR_LINKST) 240 rc = 1; 241 242 return rc; 243} 244 245static int sr9700_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) 246{ 247 struct usbnet *dev = netdev_priv(netdev); 248 249 return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); 250} 251 252static const struct ethtool_ops sr9700_ethtool_ops = { 253 .get_drvinfo = usbnet_get_drvinfo, 254 .get_link = sr9700_get_link, 255 .get_msglevel = usbnet_get_msglevel, 256 .set_msglevel = usbnet_set_msglevel, 257 .get_eeprom_len = sr9700_get_eeprom_len, 258 .get_eeprom = sr9700_get_eeprom, 259 .nway_reset = usbnet_nway_reset, 260 .get_link_ksettings = usbnet_get_link_ksettings_mii, 261 .set_link_ksettings = usbnet_set_link_ksettings_mii, 262}; 263 264static void sr9700_set_multicast(struct net_device *netdev) 265{ 266 struct usbnet *dev = netdev_priv(netdev); 267 /* rx_ctl setting : enable, disable_long, disable_crc */ 268 u8 rx_ctl = RCR_RXEN | RCR_DIS_CRC | RCR_DIS_LONG; 269 270 if (netdev->flags & IFF_PROMISC) 271 rx_ctl |= RCR_PRMSC; 272 else if (netdev->flags & IFF_ALLMULTI || !netdev_mc_empty(netdev)) 273 /* The chip has no multicast filter */ 274 rx_ctl |= RCR_ALL; 275 276 sr_write_reg_async(dev, SR_RCR, rx_ctl); 277} 278 279static int sr9700_set_mac_address(struct net_device *netdev, void *p) 280{ 281 struct usbnet *dev = netdev_priv(netdev); 282 struct sockaddr *addr = p; 283 284 if (!is_valid_ether_addr(addr->sa_data)) { 285 netdev_err(netdev, "not setting invalid mac address %pM\n", 286 addr->sa_data); 287 return -EINVAL; 288 } 289 290 eth_hw_addr_set(netdev, addr->sa_data); 291 sr_write_async(dev, SR_PAR, 6, netdev->dev_addr); 292 293 return 0; 294} 295 296static const struct net_device_ops sr9700_netdev_ops = { 297 .ndo_open = usbnet_open, 298 .ndo_stop = usbnet_stop, 299 .ndo_start_xmit = usbnet_start_xmit, 300 .ndo_tx_timeout = usbnet_tx_timeout, 301 .ndo_change_mtu = usbnet_change_mtu, 302 .ndo_get_stats64 = dev_get_tstats64, 303 .ndo_validate_addr = eth_validate_addr, 304 .ndo_eth_ioctl = sr9700_ioctl, 305 .ndo_set_rx_mode = sr9700_set_multicast, 306 .ndo_set_mac_address = sr9700_set_mac_address, 307}; 308 309static int sr9700_bind(struct usbnet *dev, struct usb_interface *intf) 310{ 311 struct net_device *netdev; 312 struct mii_if_info *mii; 313 u8 addr[ETH_ALEN]; 314 int ret; 315 316 ret = usbnet_get_endpoints(dev, intf); 317 if (ret) 318 goto out; 319 320 netdev = dev->net; 321 322 netdev->netdev_ops = &sr9700_netdev_ops; 323 netdev->ethtool_ops = &sr9700_ethtool_ops; 324 netdev->hard_header_len += SR_TX_OVERHEAD; 325 dev->hard_mtu = netdev->mtu + netdev->hard_header_len; 326 /* bulkin buffer is preferably not less than 3K */ 327 dev->rx_urb_size = 3072; 328 329 mii = &dev->mii; 330 mii->dev = netdev; 331 mii->mdio_read = sr_mdio_read; 332 mii->mdio_write = sr_mdio_write; 333 mii->phy_id_mask = 0x1f; 334 mii->reg_num_mask = 0x1f; 335 336 sr_write_reg(dev, SR_NCR, NCR_RST); 337 udelay(20); 338 339 /* read MAC 340 * After Chip Power on, the Chip will reload the MAC from 341 * EEPROM automatically to PAR. In case there is no EEPROM externally, 342 * a default MAC address is stored in PAR for making chip work properly. 343 */ 344 if (sr_read(dev, SR_PAR, ETH_ALEN, addr) < 0) { 345 netdev_err(netdev, "Error reading MAC address\n"); 346 ret = -ENODEV; 347 goto out; 348 } 349 eth_hw_addr_set(netdev, addr); 350 351 /* power up and reset phy */ 352 sr_write_reg(dev, SR_PRR, PRR_PHY_RST); 353 /* at least 10ms, here 20ms for safe */ 354 msleep(20); 355 sr_write_reg(dev, SR_PRR, 0); 356 /* at least 1ms, here 2ms for reading right register */ 357 udelay(2 * 1000); 358 359 /* receive broadcast packets */ 360 sr9700_set_multicast(netdev); 361 362 sr_mdio_write(netdev, mii->phy_id, MII_BMCR, BMCR_RESET); 363 sr_mdio_write(netdev, mii->phy_id, MII_ADVERTISE, ADVERTISE_ALL | 364 ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP); 365 mii_nway_restart(mii); 366 367out: 368 return ret; 369} 370 371static int sr9700_rx_fixup(struct usbnet *dev, struct sk_buff *skb) 372{ 373 struct sk_buff *sr_skb; 374 int len; 375 376 /* skb content (packets) format : 377 * p0 p1 p2 ...... pm 378 * / \ 379 * / \ 380 * / \ 381 * / \ 382 * p0b0 p0b1 p0b2 p0b3 ...... p0b(n-4) p0b(n-3)...p0bn 383 * 384 * p0 : packet 0 385 * p0b0 : packet 0 byte 0 386 * 387 * b0: rx status 388 * b1: packet length (incl crc) low 389 * b2: packet length (incl crc) high 390 * b3..n-4: packet data 391 * bn-3..bn: ethernet packet crc 392 */ 393 if (unlikely(skb->len < SR_RX_OVERHEAD)) { 394 netdev_err(dev->net, "unexpected tiny rx frame\n"); 395 return 0; 396 } 397 398 /* one skb may contains multiple packets */ 399 while (skb->len > SR_RX_OVERHEAD) { 400 if (skb->data[0] != 0x40) 401 return 0; 402 403 /* ignore the CRC length */ 404 len = (skb->data[1] | (skb->data[2] << 8)) - 4; 405 406 if (len > ETH_FRAME_LEN || len > skb->len || len < 0) 407 return 0; 408 409 /* the last packet of current skb */ 410 if (skb->len == (len + SR_RX_OVERHEAD)) { 411 skb_pull(skb, 3); 412 skb->len = len; 413 skb_set_tail_pointer(skb, len); 414 return 2; 415 } 416 417 sr_skb = netdev_alloc_skb_ip_align(dev->net, len); 418 if (!sr_skb) 419 return 0; 420 421 skb_put(sr_skb, len); 422 memcpy(sr_skb->data, skb->data + 3, len); 423 usbnet_skb_return(dev, sr_skb); 424 425 skb_pull(skb, len + SR_RX_OVERHEAD); 426 } 427 428 return 0; 429} 430 431static struct sk_buff *sr9700_tx_fixup(struct usbnet *dev, struct sk_buff *skb, 432 gfp_t flags) 433{ 434 int len; 435 436 /* SR9700 can only send out one ethernet packet at once. 437 * 438 * b0 b1 b2 b3 ...... b(n-4) b(n-3)...bn 439 * 440 * b0: rx status 441 * b1: packet length (incl crc) low 442 * b2: packet length (incl crc) high 443 * b3..n-4: packet data 444 * bn-3..bn: ethernet packet crc 445 */ 446 447 len = skb->len; 448 449 if (skb_cow_head(skb, SR_TX_OVERHEAD)) { 450 dev_kfree_skb_any(skb); 451 return NULL; 452 } 453 454 __skb_push(skb, SR_TX_OVERHEAD); 455 456 /* usbnet adds padding if length is a multiple of packet size 457 * if so, adjust length value in header 458 */ 459 if ((skb->len % dev->maxpacket) == 0) 460 len++; 461 462 skb->data[0] = len; 463 skb->data[1] = len >> 8; 464 465 return skb; 466} 467 468static void sr9700_status(struct usbnet *dev, struct urb *urb) 469{ 470 int link; 471 u8 *buf; 472 473 /* format: 474 b0: net status 475 b1: tx status 1 476 b2: tx status 2 477 b3: rx status 478 b4: rx overflow 479 b5: rx count 480 b6: tx count 481 b7: gpr 482 */ 483 484 if (urb->actual_length < 8) 485 return; 486 487 buf = urb->transfer_buffer; 488 489 link = !!(buf[0] & 0x40); 490 if (netif_carrier_ok(dev->net) != link) { 491 usbnet_link_change(dev, link, 1); 492 netdev_dbg(dev->net, "Link Status is: %d\n", link); 493 } 494} 495 496static int sr9700_link_reset(struct usbnet *dev) 497{ 498 struct ethtool_cmd ecmd; 499 500 mii_check_media(&dev->mii, 1, 1); 501 mii_ethtool_gset(&dev->mii, &ecmd); 502 503 netdev_dbg(dev->net, "link_reset() speed: %d duplex: %d\n", 504 ecmd.speed, ecmd.duplex); 505 506 return 0; 507} 508 509static const struct driver_info sr9700_driver_info = { 510 .description = "CoreChip SR9700 USB Ethernet", 511 .flags = FLAG_ETHER, 512 .bind = sr9700_bind, 513 .rx_fixup = sr9700_rx_fixup, 514 .tx_fixup = sr9700_tx_fixup, 515 .status = sr9700_status, 516 .link_reset = sr9700_link_reset, 517 .reset = sr9700_link_reset, 518}; 519 520static const struct usb_device_id products[] = { 521 { 522 USB_DEVICE(0x0fe6, 0x9700), /* SR9700 device */ 523 .driver_info = (unsigned long)&sr9700_driver_info, 524 }, 525 { 526 /* SR9700 with virtual driver CD-ROM - interface 0 is the CD-ROM device */ 527 USB_DEVICE_INTERFACE_NUMBER(0x0fe6, 0x9702, 1), 528 .driver_info = (unsigned long)&sr9700_driver_info, 529 }, 530 {}, /* END */ 531}; 532 533MODULE_DEVICE_TABLE(usb, products); 534 535static struct usb_driver sr9700_usb_driver = { 536 .name = "sr9700", 537 .id_table = products, 538 .probe = usbnet_probe, 539 .disconnect = usbnet_disconnect, 540 .suspend = usbnet_suspend, 541 .resume = usbnet_resume, 542 .disable_hub_initiated_lpm = 1, 543}; 544 545module_usb_driver(sr9700_usb_driver); 546 547MODULE_AUTHOR("liujl <liujunliang_ljl@163.com>"); 548MODULE_DESCRIPTION("SR9700 one chip USB 1.1 USB to Ethernet device from http://www.corechip-sz.com/"); 549MODULE_LICENSE("GPL");
~/
Read-only file preview.