Lines Matching +full:10 +full:base +full:- +full:t1x
1 // SPDX-License-Identifier: GPL-2.0+
3 * OPEN Alliance 10BASE‑T1x MAC‑PHY Serial Interface framework
48 /* PHY Clause 22 registers base address and mask */
108 /* Internal structure for MAC-PHY drivers */
165 xfer.tx_buf = tc6->spi_data_tx_buf; in oa_tc6_spi_transfer()
166 xfer.rx_buf = tc6->spi_data_rx_buf; in oa_tc6_spi_transfer()
168 xfer.tx_buf = tc6->spi_ctrl_tx_buf; in oa_tc6_spi_transfer()
169 xfer.rx_buf = tc6->spi_ctrl_rx_buf; in oa_tc6_spi_transfer()
176 return spi_sync(tc6->spi, &msg); in oa_tc6_spi_transfer()
182 * http://www-graphics.stanford.edu/~seander/bithacks.html in oa_tc6_get_parity()
202 FIELD_PREP(OA_TC6_CTRL_HEADER_LENGTH, length - 1); in oa_tc6_prepare_ctrl_header()
212 __be32 *tx_buf = tc6->spi_ctrl_tx_buf + OA_TC6_CTRL_HEADER_SIZE; in oa_tc6_update_ctrl_write_data()
231 __be32 *tx_buf = tc6->spi_ctrl_tx_buf; in oa_tc6_prepare_ctrl_spi_buf()
241 u8 *tx_buf = tc6->spi_ctrl_tx_buf; in oa_tc6_check_ctrl_write_reply()
242 u8 *rx_buf = tc6->spi_ctrl_rx_buf; in oa_tc6_check_ctrl_write_reply()
249 if (memcmp(tx_buf, rx_buf, size - OA_TC6_CTRL_IGNORED_SIZE)) in oa_tc6_check_ctrl_write_reply()
250 return -EPROTO; in oa_tc6_check_ctrl_write_reply()
257 u32 *rx_buf = tc6->spi_ctrl_rx_buf + OA_TC6_CTRL_IGNORED_SIZE; in oa_tc6_check_ctrl_read_reply()
258 u32 *tx_buf = tc6->spi_ctrl_tx_buf; in oa_tc6_check_ctrl_read_reply()
264 return -EPROTO; in oa_tc6_check_ctrl_read_reply()
272 __be32 *rx_buf = tc6->spi_ctrl_rx_buf + OA_TC6_CTRL_IGNORED_SIZE + in oa_tc6_copy_ctrl_read_data()
293 dev_err(&tc6->spi->dev, "SPI transfer failed for control: %d\n", in oa_tc6_perform_ctrl()
313 * oa_tc6_read_registers - function for reading multiple consecutive registers.
315 * @address: address of the first register to be read in the MAC-PHY.
329 dev_err(&tc6->spi->dev, "Invalid register length parameter\n"); in oa_tc6_read_registers()
330 return -EINVAL; in oa_tc6_read_registers()
333 mutex_lock(&tc6->spi_ctrl_lock); in oa_tc6_read_registers()
336 mutex_unlock(&tc6->spi_ctrl_lock); in oa_tc6_read_registers()
343 * oa_tc6_read_register - function for reading a MAC-PHY register.
345 * @address: register address of the MAC-PHY to be read.
346 * @value: value read from the @address register address of the MAC-PHY.
357 * oa_tc6_write_registers - function for writing multiple consecutive registers.
359 * @address: address of the first register to be written in the MAC-PHY.
373 dev_err(&tc6->spi->dev, "Invalid register length parameter\n"); in oa_tc6_write_registers()
374 return -EINVAL; in oa_tc6_write_registers()
377 mutex_lock(&tc6->spi_ctrl_lock); in oa_tc6_write_registers()
380 mutex_unlock(&tc6->spi_ctrl_lock); in oa_tc6_write_registers()
387 * oa_tc6_write_register - function for writing a MAC-PHY register.
389 * @address: register address of the MAC-PHY to be written.
390 * @value: value to be written in the @address register address of the MAC-PHY.
410 return -ENODEV; in oa_tc6_check_phy_reg_direct_access_capability()
417 phy_print_status(netdev->phydev); in oa_tc6_handle_link_change()
422 struct oa_tc6 *tc6 = bus->priv; in oa_tc6_mdiobus_read()
438 struct oa_tc6 *tc6 = bus->priv; in oa_tc6_mdiobus_write()
459 return -EOPNOTSUPP; in oa_tc6_get_phy_c45_mms()
466 struct oa_tc6 *tc6 = bus->priv; in oa_tc6_mdiobus_read_c45()
484 struct oa_tc6 *tc6 = bus->priv; in oa_tc6_mdiobus_write_c45()
498 tc6->mdiobus = mdiobus_alloc(); in oa_tc6_mdiobus_register()
499 if (!tc6->mdiobus) { in oa_tc6_mdiobus_register()
500 netdev_err(tc6->netdev, "MDIO bus alloc failed\n"); in oa_tc6_mdiobus_register()
501 return -ENOMEM; in oa_tc6_mdiobus_register()
504 tc6->mdiobus->priv = tc6; in oa_tc6_mdiobus_register()
505 tc6->mdiobus->read = oa_tc6_mdiobus_read; in oa_tc6_mdiobus_register()
506 tc6->mdiobus->write = oa_tc6_mdiobus_write; in oa_tc6_mdiobus_register()
507 /* OPEN Alliance 10BASE-T1x compliance MAC-PHYs will have both C22 and in oa_tc6_mdiobus_register()
517 tc6->mdiobus->read_c45 = oa_tc6_mdiobus_read_c45; in oa_tc6_mdiobus_register()
518 tc6->mdiobus->write_c45 = oa_tc6_mdiobus_write_c45; in oa_tc6_mdiobus_register()
519 tc6->mdiobus->name = "oa-tc6-mdiobus"; in oa_tc6_mdiobus_register()
520 tc6->mdiobus->parent = tc6->dev; in oa_tc6_mdiobus_register()
522 snprintf(tc6->mdiobus->id, ARRAY_SIZE(tc6->mdiobus->id), "%s", in oa_tc6_mdiobus_register()
523 dev_name(&tc6->spi->dev)); in oa_tc6_mdiobus_register()
525 ret = mdiobus_register(tc6->mdiobus); in oa_tc6_mdiobus_register()
527 netdev_err(tc6->netdev, "Could not register MDIO bus\n"); in oa_tc6_mdiobus_register()
528 mdiobus_free(tc6->mdiobus); in oa_tc6_mdiobus_register()
537 mdiobus_unregister(tc6->mdiobus); in oa_tc6_mdiobus_unregister()
538 mdiobus_free(tc6->mdiobus); in oa_tc6_mdiobus_unregister()
547 netdev_err(tc6->netdev, in oa_tc6_phy_init()
548 "Direct PHY register access is not supported by the MAC-PHY\n"); in oa_tc6_phy_init()
556 tc6->phydev = phy_find_first(tc6->mdiobus); in oa_tc6_phy_init()
557 if (!tc6->phydev) { in oa_tc6_phy_init()
558 netdev_err(tc6->netdev, "No PHY found\n"); in oa_tc6_phy_init()
560 return -ENODEV; in oa_tc6_phy_init()
563 tc6->phydev->is_internal = true; in oa_tc6_phy_init()
564 ret = phy_connect_direct(tc6->netdev, tc6->phydev, in oa_tc6_phy_init()
568 netdev_err(tc6->netdev, "Can't attach PHY to %s\n", in oa_tc6_phy_init()
569 tc6->mdiobus->id); in oa_tc6_phy_init()
574 phy_attached_info(tc6->netdev->phydev); in oa_tc6_phy_init()
581 phy_disconnect(tc6->phydev); in oa_tc6_phy_exit()
592 dev_err(&tc6->spi->dev, "STATUS0 register read failed: %d\n", in oa_tc6_read_status0()
615 return -ENODEV; in oa_tc6_sw_reset_macphy()
655 if (tc6->rx_skb) { in oa_tc6_cleanup_ongoing_rx_skb()
656 tc6->netdev->stats.rx_dropped++; in oa_tc6_cleanup_ongoing_rx_skb()
657 kfree_skb(tc6->rx_skb); in oa_tc6_cleanup_ongoing_rx_skb()
658 tc6->rx_skb = NULL; in oa_tc6_cleanup_ongoing_rx_skb()
664 if (tc6->ongoing_tx_skb) { in oa_tc6_cleanup_ongoing_tx_skb()
665 tc6->netdev->stats.tx_dropped++; in oa_tc6_cleanup_ongoing_tx_skb()
666 kfree_skb(tc6->ongoing_tx_skb); in oa_tc6_cleanup_ongoing_tx_skb()
667 tc6->ongoing_tx_skb = NULL; in oa_tc6_cleanup_ongoing_tx_skb()
678 netdev_err(tc6->netdev, "STATUS0 register read failed: %d\n", in oa_tc6_process_extended_status()
686 netdev_err(tc6->netdev, "STATUS0 register write failed: %d\n", in oa_tc6_process_extended_status()
692 tc6->rx_buf_overflow = true; in oa_tc6_process_extended_status()
695 tc6->netdev->name); in oa_tc6_process_extended_status()
696 return -EAGAIN; in oa_tc6_process_extended_status()
699 netdev_err(tc6->netdev, "Transmit protocol error\n"); in oa_tc6_process_extended_status()
700 return -ENODEV; in oa_tc6_process_extended_status()
703 * non-recoverable errors. They will be handled in the next version. in oa_tc6_process_extended_status()
706 netdev_err(tc6->netdev, "Loss of frame error\n"); in oa_tc6_process_extended_status()
707 return -ENODEV; in oa_tc6_process_extended_status()
710 netdev_err(tc6->netdev, "Header error\n"); in oa_tc6_process_extended_status()
711 return -ENODEV; in oa_tc6_process_extended_status()
721 * 2. errors if any from MAC-PHY in oa_tc6_process_rx_chunk_footer()
724 tc6->tx_credits = FIELD_GET(OA_TC6_DATA_FOOTER_TX_CREDITS, footer); in oa_tc6_process_rx_chunk_footer()
725 tc6->rx_chunks_available = FIELD_GET(OA_TC6_DATA_FOOTER_RX_CHUNKS, in oa_tc6_process_rx_chunk_footer()
736 * are treated as non-recoverable errors. They will be handled in the in oa_tc6_process_rx_chunk_footer()
740 netdev_err(tc6->netdev, "Rxd header bad error\n"); in oa_tc6_process_rx_chunk_footer()
741 return -ENODEV; in oa_tc6_process_rx_chunk_footer()
745 netdev_err(tc6->netdev, "Config unsync error\n"); in oa_tc6_process_rx_chunk_footer()
746 return -ENODEV; in oa_tc6_process_rx_chunk_footer()
754 tc6->rx_skb->protocol = eth_type_trans(tc6->rx_skb, tc6->netdev); in oa_tc6_submit_rx_skb()
755 tc6->netdev->stats.rx_packets++; in oa_tc6_submit_rx_skb()
756 tc6->netdev->stats.rx_bytes += tc6->rx_skb->len; in oa_tc6_submit_rx_skb()
758 netif_rx(tc6->rx_skb); in oa_tc6_submit_rx_skb()
760 tc6->rx_skb = NULL; in oa_tc6_submit_rx_skb()
765 memcpy(skb_put(tc6->rx_skb, length), payload, length); in oa_tc6_update_rx_skb()
770 tc6->rx_skb = netdev_alloc_skb_ip_align(tc6->netdev, tc6->netdev->mtu + in oa_tc6_allocate_rx_skb()
772 if (!tc6->rx_skb) { in oa_tc6_allocate_rx_skb()
773 tc6->netdev->stats.rx_dropped++; in oa_tc6_allocate_rx_skb()
774 return -ENOMEM; in oa_tc6_allocate_rx_skb()
834 if (start_valid && tc6->rx_buf_overflow) in oa_tc6_prcs_rx_chunk_payload()
835 tc6->rx_buf_overflow = false; in oa_tc6_prcs_rx_chunk_payload()
837 if (tc6->rx_buf_overflow) in oa_tc6_prcs_rx_chunk_payload()
842 size = end_byte_offset + 1 - start_byte_offset; in oa_tc6_prcs_rx_chunk_payload()
850 size = OA_TC6_CHUNK_PAYLOAD_SIZE - start_byte_offset; in oa_tc6_prcs_rx_chunk_payload()
871 if (tc6->rx_skb) { in oa_tc6_prcs_rx_chunk_payload()
875 size = OA_TC6_CHUNK_PAYLOAD_SIZE - start_byte_offset; in oa_tc6_prcs_rx_chunk_payload()
889 u8 *rx_buf = tc6->spi_data_rx_buf; in oa_tc6_get_rx_chunk_footer()
918 u8 *payload = tc6->spi_data_rx_buf + i * in oa_tc6_process_spi_data_rx_buf()
951 __be32 *tx_buf = tc6->spi_data_tx_buf + tc6->spi_data_tx_buf_offset; in oa_tc6_add_tx_skb_to_spi_buf()
952 u16 remaining_len = tc6->ongoing_tx_skb->len - tc6->tx_skb_offset; in oa_tc6_add_tx_skb_to_spi_buf()
953 u8 *tx_skb_data = tc6->ongoing_tx_skb->data + tc6->tx_skb_offset; in oa_tc6_add_tx_skb_to_spi_buf()
966 if (!tc6->tx_skb_offset) in oa_tc6_add_tx_skb_to_spi_buf()
977 tc6->tx_skb_offset += length_to_copy; in oa_tc6_add_tx_skb_to_spi_buf()
982 if (tc6->ongoing_tx_skb->len == tc6->tx_skb_offset) { in oa_tc6_add_tx_skb_to_spi_buf()
984 end_byte_offset = length_to_copy - 1; in oa_tc6_add_tx_skb_to_spi_buf()
985 tc6->tx_skb_offset = 0; in oa_tc6_add_tx_skb_to_spi_buf()
986 tc6->netdev->stats.tx_bytes += tc6->ongoing_tx_skb->len; in oa_tc6_add_tx_skb_to_spi_buf()
987 tc6->netdev->stats.tx_packets++; in oa_tc6_add_tx_skb_to_spi_buf()
988 kfree_skb(tc6->ongoing_tx_skb); in oa_tc6_add_tx_skb_to_spi_buf()
989 tc6->ongoing_tx_skb = NULL; in oa_tc6_add_tx_skb_to_spi_buf()
994 tc6->spi_data_tx_buf_offset += OA_TC6_CHUNK_SIZE; in oa_tc6_add_tx_skb_to_spi_buf()
1004 for (used_tx_credits = 0; used_tx_credits < tc6->tx_credits; in oa_tc6_prepare_spi_tx_buf_for_tx_skbs()
1006 if (!tc6->ongoing_tx_skb) { in oa_tc6_prepare_spi_tx_buf_for_tx_skbs()
1007 tc6->ongoing_tx_skb = tc6->waiting_tx_skb; in oa_tc6_prepare_spi_tx_buf_for_tx_skbs()
1008 tc6->waiting_tx_skb = NULL; in oa_tc6_prepare_spi_tx_buf_for_tx_skbs()
1010 if (!tc6->ongoing_tx_skb) in oa_tc6_prepare_spi_tx_buf_for_tx_skbs()
1027 while (needed_empty_chunks--) { in oa_tc6_add_empty_chunks_to_spi_buf()
1028 __be32 *tx_buf = tc6->spi_data_tx_buf + in oa_tc6_add_empty_chunks_to_spi_buf()
1029 tc6->spi_data_tx_buf_offset; in oa_tc6_add_empty_chunks_to_spi_buf()
1032 tc6->spi_data_tx_buf_offset += OA_TC6_CHUNK_SIZE; in oa_tc6_add_empty_chunks_to_spi_buf()
1045 if (tx_chunks >= tc6->rx_chunks_available) in oa_tc6_prepare_spi_tx_buf_for_rx_chunks()
1048 needed_empty_chunks = tc6->rx_chunks_available - tx_chunks; in oa_tc6_prepare_spi_tx_buf_for_rx_chunks()
1062 tc6->spi_data_tx_buf_offset = 0; in oa_tc6_try_spi_transfer()
1064 if (tc6->ongoing_tx_skb || tc6->waiting_tx_skb) in oa_tc6_try_spi_transfer()
1069 if (tc6->int_flag) { in oa_tc6_try_spi_transfer()
1070 tc6->int_flag = false; in oa_tc6_try_spi_transfer()
1082 netdev_err(tc6->netdev, "SPI data transfer failed: %d\n", in oa_tc6_try_spi_transfer()
1089 if (ret == -EAGAIN) in oa_tc6_try_spi_transfer()
1094 netdev_err(tc6->netdev, "Device error: %d\n", ret); in oa_tc6_try_spi_transfer()
1098 if (!tc6->waiting_tx_skb && netif_queue_stopped(tc6->netdev)) in oa_tc6_try_spi_transfer()
1099 netif_wake_queue(tc6->netdev); in oa_tc6_try_spi_transfer()
1111 /* This kthread will be waken up if there is a tx skb or mac-phy in oa_tc6_spi_thread_handler()
1114 wait_event_interruptible(tc6->spi_wq, tc6->waiting_tx_skb || in oa_tc6_spi_thread_handler()
1115 tc6->int_flag || in oa_tc6_spi_thread_handler()
1142 tc6->tx_credits = FIELD_GET(BUFFER_STATUS_TX_CREDITS_AVAILABLE, value); in oa_tc6_update_buffer_status_from_register()
1143 tc6->rx_chunks_available = FIELD_GET(BUFFER_STATUS_RX_CHUNKS_AVAILABLE, in oa_tc6_update_buffer_status_from_register()
1153 /* MAC-PHY interrupt can occur for the following reasons. in oa_tc6_macphy_isr()
1154 * - availability of tx credits if it was 0 before and not reported in in oa_tc6_macphy_isr()
1156 * - availability of rx chunks if it was 0 before and not reported in in oa_tc6_macphy_isr()
1158 * - extended status event not reported in the previous rx footer. in oa_tc6_macphy_isr()
1160 tc6->int_flag = true; in oa_tc6_macphy_isr()
1162 wake_up_interruptible(&tc6->spi_wq); in oa_tc6_macphy_isr()
1168 * oa_tc6_zero_align_receive_frame_enable - function to enable zero align
1183 /* Set Zero-Align Receive Frame Enable */ in oa_tc6_zero_align_receive_frame_enable()
1191 * oa_tc6_start_xmit - function for sending the tx skb which consists ethernet
1201 if (tc6->waiting_tx_skb) { in oa_tc6_start_xmit()
1202 netif_stop_queue(tc6->netdev); in oa_tc6_start_xmit()
1208 tc6->netdev->stats.tx_dropped++; in oa_tc6_start_xmit()
1212 tc6->waiting_tx_skb = skb; in oa_tc6_start_xmit()
1215 wake_up_interruptible(&tc6->spi_wq); in oa_tc6_start_xmit()
1222 * oa_tc6_init - allocates and initializes oa_tc6 structure.
1226 * Return: pointer reference to the oa_tc6 structure if the MAC-PHY
1234 tc6 = devm_kzalloc(&spi->dev, sizeof(*tc6), GFP_KERNEL); in oa_tc6_init()
1238 tc6->spi = spi; in oa_tc6_init()
1239 tc6->netdev = netdev; in oa_tc6_init()
1240 SET_NETDEV_DEV(netdev, &spi->dev); in oa_tc6_init()
1241 mutex_init(&tc6->spi_ctrl_lock); in oa_tc6_init()
1244 tc6->spi->rt = true; in oa_tc6_init()
1245 spi_setup(tc6->spi); in oa_tc6_init()
1247 tc6->spi_ctrl_tx_buf = devm_kzalloc(&tc6->spi->dev, in oa_tc6_init()
1250 if (!tc6->spi_ctrl_tx_buf) in oa_tc6_init()
1253 tc6->spi_ctrl_rx_buf = devm_kzalloc(&tc6->spi->dev, in oa_tc6_init()
1256 if (!tc6->spi_ctrl_rx_buf) in oa_tc6_init()
1259 tc6->spi_data_tx_buf = devm_kzalloc(&tc6->spi->dev, in oa_tc6_init()
1262 if (!tc6->spi_data_tx_buf) in oa_tc6_init()
1265 tc6->spi_data_rx_buf = devm_kzalloc(&tc6->spi->dev, in oa_tc6_init()
1268 if (!tc6->spi_data_rx_buf) in oa_tc6_init()
1273 dev_err(&tc6->spi->dev, in oa_tc6_init()
1274 "MAC-PHY software reset failed: %d\n", ret); in oa_tc6_init()
1280 dev_err(&tc6->spi->dev, in oa_tc6_init()
1281 "MAC-PHY error interrupts unmask failed: %d\n", ret); in oa_tc6_init()
1287 dev_err(&tc6->spi->dev, in oa_tc6_init()
1294 dev_err(&tc6->spi->dev, "Failed to enable data transfer: %d\n", in oa_tc6_init()
1301 dev_err(&tc6->spi->dev, in oa_tc6_init()
1306 init_waitqueue_head(&tc6->spi_wq); in oa_tc6_init()
1308 tc6->spi_thread = kthread_run(oa_tc6_spi_thread_handler, tc6, in oa_tc6_init()
1309 "oa-tc6-spi-thread"); in oa_tc6_init()
1310 if (IS_ERR(tc6->spi_thread)) { in oa_tc6_init()
1311 dev_err(&tc6->spi->dev, "Failed to create SPI thread\n"); in oa_tc6_init()
1315 sched_set_fifo(tc6->spi_thread); in oa_tc6_init()
1317 ret = devm_request_irq(&tc6->spi->dev, tc6->spi->irq, oa_tc6_macphy_isr, in oa_tc6_init()
1318 IRQF_TRIGGER_FALLING, dev_name(&tc6->spi->dev), in oa_tc6_init()
1321 dev_err(&tc6->spi->dev, "Failed to request macphy isr %d\n", in oa_tc6_init()
1326 /* oa_tc6_sw_reset_macphy() function resets and clears the MAC-PHY reset in oa_tc6_init()
1328 * remain asserted until MAC-PHY receives a data chunk. So performing an in oa_tc6_init()
1332 tc6->int_flag = true; in oa_tc6_init()
1333 wake_up_interruptible(&tc6->spi_wq); in oa_tc6_init()
1338 kthread_stop(tc6->spi_thread); in oa_tc6_init()
1346 * oa_tc6_exit - exit function.
1352 kthread_stop(tc6->spi_thread); in oa_tc6_exit()
1353 dev_kfree_skb_any(tc6->ongoing_tx_skb); in oa_tc6_exit()
1354 dev_kfree_skb_any(tc6->waiting_tx_skb); in oa_tc6_exit()
1355 dev_kfree_skb_any(tc6->rx_skb); in oa_tc6_exit()
1359 MODULE_DESCRIPTION("OPEN Alliance 10BASE‑T1x MAC‑PHY Serial Interface Lib");