Lines Matching +full:10 +full:base +full:- +full:t1x

1 // SPDX-License-Identifier: GPL-2.0+
3 * OPEN Alliance 10BASET1x MAC‑PHY Serial Interface framework
48 /* PHY Clause 22 registers base address and mask */
108 /* Internal structure for MAC-PHY drivers */
166 xfer.tx_buf = tc6->spi_data_tx_buf; in oa_tc6_spi_transfer()
167 xfer.rx_buf = tc6->spi_data_rx_buf; in oa_tc6_spi_transfer()
169 xfer.tx_buf = tc6->spi_ctrl_tx_buf; in oa_tc6_spi_transfer()
170 xfer.rx_buf = tc6->spi_ctrl_rx_buf; in oa_tc6_spi_transfer()
177 return spi_sync(tc6->spi, &msg); in oa_tc6_spi_transfer()
183 * http://www-graphics.stanford.edu/~seander/bithacks.html in oa_tc6_get_parity()
203 FIELD_PREP(OA_TC6_CTRL_HEADER_LENGTH, length - 1); in oa_tc6_prepare_ctrl_header()
213 __be32 *tx_buf = tc6->spi_ctrl_tx_buf + OA_TC6_CTRL_HEADER_SIZE; in oa_tc6_update_ctrl_write_data()
232 __be32 *tx_buf = tc6->spi_ctrl_tx_buf; in oa_tc6_prepare_ctrl_spi_buf()
242 u8 *tx_buf = tc6->spi_ctrl_tx_buf; in oa_tc6_check_ctrl_write_reply()
243 u8 *rx_buf = tc6->spi_ctrl_rx_buf; in oa_tc6_check_ctrl_write_reply()
250 if (memcmp(tx_buf, rx_buf, size - OA_TC6_CTRL_IGNORED_SIZE)) in oa_tc6_check_ctrl_write_reply()
251 return -EPROTO; in oa_tc6_check_ctrl_write_reply()
258 u32 *rx_buf = tc6->spi_ctrl_rx_buf + OA_TC6_CTRL_IGNORED_SIZE; in oa_tc6_check_ctrl_read_reply()
259 u32 *tx_buf = tc6->spi_ctrl_tx_buf; in oa_tc6_check_ctrl_read_reply()
265 return -EPROTO; in oa_tc6_check_ctrl_read_reply()
273 __be32 *rx_buf = tc6->spi_ctrl_rx_buf + OA_TC6_CTRL_IGNORED_SIZE + in oa_tc6_copy_ctrl_read_data()
294 dev_err(&tc6->spi->dev, "SPI transfer failed for control: %d\n", in oa_tc6_perform_ctrl()
314 * oa_tc6_read_registers - function for reading multiple consecutive registers.
316 * @address: address of the first register to be read in the MAC-PHY.
330 dev_err(&tc6->spi->dev, "Invalid register length parameter\n"); in oa_tc6_read_registers()
331 return -EINVAL; in oa_tc6_read_registers()
334 mutex_lock(&tc6->spi_ctrl_lock); in oa_tc6_read_registers()
337 mutex_unlock(&tc6->spi_ctrl_lock); in oa_tc6_read_registers()
344 * oa_tc6_read_register - function for reading a MAC-PHY register.
346 * @address: register address of the MAC-PHY to be read.
347 * @value: value read from the @address register address of the MAC-PHY.
358 * oa_tc6_write_registers - function for writing multiple consecutive registers.
360 * @address: address of the first register to be written in the MAC-PHY.
374 dev_err(&tc6->spi->dev, "Invalid register length parameter\n"); in oa_tc6_write_registers()
375 return -EINVAL; in oa_tc6_write_registers()
378 mutex_lock(&tc6->spi_ctrl_lock); in oa_tc6_write_registers()
381 mutex_unlock(&tc6->spi_ctrl_lock); in oa_tc6_write_registers()
388 * oa_tc6_write_register - function for writing a MAC-PHY register.
390 * @address: register address of the MAC-PHY to be written.
391 * @value: value to be written in the @address register address of the MAC-PHY.
411 return -ENODEV; in oa_tc6_check_phy_reg_direct_access_capability()
418 phy_print_status(netdev->phydev); in oa_tc6_handle_link_change()
423 struct oa_tc6 *tc6 = bus->priv; in oa_tc6_mdiobus_read()
439 struct oa_tc6 *tc6 = bus->priv; in oa_tc6_mdiobus_write()
460 return -EOPNOTSUPP; in oa_tc6_get_phy_c45_mms()
467 struct oa_tc6 *tc6 = bus->priv; in oa_tc6_mdiobus_read_c45()
485 struct oa_tc6 *tc6 = bus->priv; in oa_tc6_mdiobus_write_c45()
499 tc6->mdiobus = mdiobus_alloc(); in oa_tc6_mdiobus_register()
500 if (!tc6->mdiobus) { in oa_tc6_mdiobus_register()
501 netdev_err(tc6->netdev, "MDIO bus alloc failed\n"); in oa_tc6_mdiobus_register()
502 return -ENOMEM; in oa_tc6_mdiobus_register()
505 tc6->mdiobus->priv = tc6; in oa_tc6_mdiobus_register()
506 tc6->mdiobus->read = oa_tc6_mdiobus_read; in oa_tc6_mdiobus_register()
507 tc6->mdiobus->write = oa_tc6_mdiobus_write; in oa_tc6_mdiobus_register()
508 /* OPEN Alliance 10BASE-T1x compliance MAC-PHYs will have both C22 and in oa_tc6_mdiobus_register()
518 tc6->mdiobus->read_c45 = oa_tc6_mdiobus_read_c45; in oa_tc6_mdiobus_register()
519 tc6->mdiobus->write_c45 = oa_tc6_mdiobus_write_c45; in oa_tc6_mdiobus_register()
520 tc6->mdiobus->name = "oa-tc6-mdiobus"; in oa_tc6_mdiobus_register()
521 tc6->mdiobus->parent = tc6->dev; in oa_tc6_mdiobus_register()
523 snprintf(tc6->mdiobus->id, ARRAY_SIZE(tc6->mdiobus->id), "%s", in oa_tc6_mdiobus_register()
524 dev_name(&tc6->spi->dev)); in oa_tc6_mdiobus_register()
526 ret = mdiobus_register(tc6->mdiobus); in oa_tc6_mdiobus_register()
528 netdev_err(tc6->netdev, "Could not register MDIO bus\n"); in oa_tc6_mdiobus_register()
529 mdiobus_free(tc6->mdiobus); in oa_tc6_mdiobus_register()
538 mdiobus_unregister(tc6->mdiobus); in oa_tc6_mdiobus_unregister()
539 mdiobus_free(tc6->mdiobus); in oa_tc6_mdiobus_unregister()
548 netdev_err(tc6->netdev, in oa_tc6_phy_init()
549 "Direct PHY register access is not supported by the MAC-PHY\n"); in oa_tc6_phy_init()
557 tc6->phydev = phy_find_first(tc6->mdiobus); in oa_tc6_phy_init()
558 if (!tc6->phydev) { in oa_tc6_phy_init()
559 netdev_err(tc6->netdev, "No PHY found\n"); in oa_tc6_phy_init()
561 return -ENODEV; in oa_tc6_phy_init()
564 tc6->phydev->is_internal = true; in oa_tc6_phy_init()
565 ret = phy_connect_direct(tc6->netdev, tc6->phydev, in oa_tc6_phy_init()
569 netdev_err(tc6->netdev, "Can't attach PHY to %s\n", in oa_tc6_phy_init()
570 tc6->mdiobus->id); in oa_tc6_phy_init()
575 phy_attached_info(tc6->netdev->phydev); in oa_tc6_phy_init()
582 phy_disconnect(tc6->phydev); in oa_tc6_phy_exit()
593 dev_err(&tc6->spi->dev, "STATUS0 register read failed: %d\n", in oa_tc6_read_status0()
616 return -ENODEV; in oa_tc6_sw_reset_macphy()
656 if (tc6->rx_skb) { in oa_tc6_cleanup_ongoing_rx_skb()
657 tc6->netdev->stats.rx_dropped++; in oa_tc6_cleanup_ongoing_rx_skb()
658 kfree_skb(tc6->rx_skb); in oa_tc6_cleanup_ongoing_rx_skb()
659 tc6->rx_skb = NULL; in oa_tc6_cleanup_ongoing_rx_skb()
665 if (tc6->ongoing_tx_skb) { in oa_tc6_cleanup_ongoing_tx_skb()
666 tc6->netdev->stats.tx_dropped++; in oa_tc6_cleanup_ongoing_tx_skb()
667 kfree_skb(tc6->ongoing_tx_skb); in oa_tc6_cleanup_ongoing_tx_skb()
668 tc6->ongoing_tx_skb = NULL; in oa_tc6_cleanup_ongoing_tx_skb()
679 netdev_err(tc6->netdev, "STATUS0 register read failed: %d\n", in oa_tc6_process_extended_status()
687 netdev_err(tc6->netdev, "STATUS0 register write failed: %d\n", in oa_tc6_process_extended_status()
693 tc6->rx_buf_overflow = true; in oa_tc6_process_extended_status()
696 tc6->netdev->name); in oa_tc6_process_extended_status()
697 return -EAGAIN; in oa_tc6_process_extended_status()
700 netdev_err(tc6->netdev, "Transmit protocol error\n"); in oa_tc6_process_extended_status()
701 return -ENODEV; in oa_tc6_process_extended_status()
704 * non-recoverable errors. They will be handled in the next version. in oa_tc6_process_extended_status()
707 netdev_err(tc6->netdev, "Loss of frame error\n"); in oa_tc6_process_extended_status()
708 return -ENODEV; in oa_tc6_process_extended_status()
711 netdev_err(tc6->netdev, "Header error\n"); in oa_tc6_process_extended_status()
712 return -ENODEV; in oa_tc6_process_extended_status()
722 * 2. errors if any from MAC-PHY in oa_tc6_process_rx_chunk_footer()
725 tc6->tx_credits = FIELD_GET(OA_TC6_DATA_FOOTER_TX_CREDITS, footer); in oa_tc6_process_rx_chunk_footer()
726 tc6->rx_chunks_available = FIELD_GET(OA_TC6_DATA_FOOTER_RX_CHUNKS, in oa_tc6_process_rx_chunk_footer()
737 * are treated as non-recoverable errors. They will be handled in the in oa_tc6_process_rx_chunk_footer()
741 netdev_err(tc6->netdev, "Rxd header bad error\n"); in oa_tc6_process_rx_chunk_footer()
742 return -ENODEV; in oa_tc6_process_rx_chunk_footer()
746 netdev_err(tc6->netdev, "Config unsync error\n"); in oa_tc6_process_rx_chunk_footer()
747 return -ENODEV; in oa_tc6_process_rx_chunk_footer()
755 tc6->rx_skb->protocol = eth_type_trans(tc6->rx_skb, tc6->netdev); in oa_tc6_submit_rx_skb()
756 tc6->netdev->stats.rx_packets++; in oa_tc6_submit_rx_skb()
757 tc6->netdev->stats.rx_bytes += tc6->rx_skb->len; in oa_tc6_submit_rx_skb()
759 netif_rx(tc6->rx_skb); in oa_tc6_submit_rx_skb()
761 tc6->rx_skb = NULL; in oa_tc6_submit_rx_skb()
766 memcpy(skb_put(tc6->rx_skb, length), payload, length); in oa_tc6_update_rx_skb()
771 tc6->rx_skb = netdev_alloc_skb_ip_align(tc6->netdev, tc6->netdev->mtu + in oa_tc6_allocate_rx_skb()
773 if (!tc6->rx_skb) { in oa_tc6_allocate_rx_skb()
774 tc6->netdev->stats.rx_dropped++; in oa_tc6_allocate_rx_skb()
775 return -ENOMEM; in oa_tc6_allocate_rx_skb()
835 if (start_valid && tc6->rx_buf_overflow) in oa_tc6_prcs_rx_chunk_payload()
836 tc6->rx_buf_overflow = false; in oa_tc6_prcs_rx_chunk_payload()
838 if (tc6->rx_buf_overflow) in oa_tc6_prcs_rx_chunk_payload()
843 size = end_byte_offset + 1 - start_byte_offset; in oa_tc6_prcs_rx_chunk_payload()
851 size = OA_TC6_CHUNK_PAYLOAD_SIZE - start_byte_offset; in oa_tc6_prcs_rx_chunk_payload()
872 if (tc6->rx_skb) { in oa_tc6_prcs_rx_chunk_payload()
876 size = OA_TC6_CHUNK_PAYLOAD_SIZE - start_byte_offset; in oa_tc6_prcs_rx_chunk_payload()
890 u8 *rx_buf = tc6->spi_data_rx_buf; in oa_tc6_get_rx_chunk_footer()
919 u8 *payload = tc6->spi_data_rx_buf + i * in oa_tc6_process_spi_data_rx_buf()
952 __be32 *tx_buf = tc6->spi_data_tx_buf + tc6->spi_data_tx_buf_offset; in oa_tc6_add_tx_skb_to_spi_buf()
953 u16 remaining_len = tc6->ongoing_tx_skb->len - tc6->tx_skb_offset; in oa_tc6_add_tx_skb_to_spi_buf()
954 u8 *tx_skb_data = tc6->ongoing_tx_skb->data + tc6->tx_skb_offset; in oa_tc6_add_tx_skb_to_spi_buf()
967 if (!tc6->tx_skb_offset) in oa_tc6_add_tx_skb_to_spi_buf()
978 tc6->tx_skb_offset += length_to_copy; in oa_tc6_add_tx_skb_to_spi_buf()
983 if (tc6->ongoing_tx_skb->len == tc6->tx_skb_offset) { in oa_tc6_add_tx_skb_to_spi_buf()
985 end_byte_offset = length_to_copy - 1; in oa_tc6_add_tx_skb_to_spi_buf()
986 tc6->tx_skb_offset = 0; in oa_tc6_add_tx_skb_to_spi_buf()
987 tc6->netdev->stats.tx_bytes += tc6->ongoing_tx_skb->len; in oa_tc6_add_tx_skb_to_spi_buf()
988 tc6->netdev->stats.tx_packets++; in oa_tc6_add_tx_skb_to_spi_buf()
989 kfree_skb(tc6->ongoing_tx_skb); in oa_tc6_add_tx_skb_to_spi_buf()
990 tc6->ongoing_tx_skb = NULL; in oa_tc6_add_tx_skb_to_spi_buf()
995 tc6->spi_data_tx_buf_offset += OA_TC6_CHUNK_SIZE; in oa_tc6_add_tx_skb_to_spi_buf()
1005 for (used_tx_credits = 0; used_tx_credits < tc6->tx_credits; in oa_tc6_prepare_spi_tx_buf_for_tx_skbs()
1007 if (!tc6->ongoing_tx_skb) { in oa_tc6_prepare_spi_tx_buf_for_tx_skbs()
1008 spin_lock_bh(&tc6->tx_skb_lock); in oa_tc6_prepare_spi_tx_buf_for_tx_skbs()
1009 tc6->ongoing_tx_skb = tc6->waiting_tx_skb; in oa_tc6_prepare_spi_tx_buf_for_tx_skbs()
1010 tc6->waiting_tx_skb = NULL; in oa_tc6_prepare_spi_tx_buf_for_tx_skbs()
1011 spin_unlock_bh(&tc6->tx_skb_lock); in oa_tc6_prepare_spi_tx_buf_for_tx_skbs()
1013 if (!tc6->ongoing_tx_skb) in oa_tc6_prepare_spi_tx_buf_for_tx_skbs()
1030 while (needed_empty_chunks--) { in oa_tc6_add_empty_chunks_to_spi_buf()
1031 __be32 *tx_buf = tc6->spi_data_tx_buf + in oa_tc6_add_empty_chunks_to_spi_buf()
1032 tc6->spi_data_tx_buf_offset; in oa_tc6_add_empty_chunks_to_spi_buf()
1035 tc6->spi_data_tx_buf_offset += OA_TC6_CHUNK_SIZE; in oa_tc6_add_empty_chunks_to_spi_buf()
1048 if (tx_chunks >= tc6->rx_chunks_available) in oa_tc6_prepare_spi_tx_buf_for_rx_chunks()
1051 needed_empty_chunks = tc6->rx_chunks_available - tx_chunks; in oa_tc6_prepare_spi_tx_buf_for_rx_chunks()
1065 tc6->spi_data_tx_buf_offset = 0; in oa_tc6_try_spi_transfer()
1067 if (tc6->ongoing_tx_skb || tc6->waiting_tx_skb) in oa_tc6_try_spi_transfer()
1072 if (tc6->int_flag) { in oa_tc6_try_spi_transfer()
1073 tc6->int_flag = false; in oa_tc6_try_spi_transfer()
1085 netdev_err(tc6->netdev, "SPI data transfer failed: %d\n", in oa_tc6_try_spi_transfer()
1092 if (ret == -EAGAIN) in oa_tc6_try_spi_transfer()
1097 netdev_err(tc6->netdev, "Device error: %d\n", ret); in oa_tc6_try_spi_transfer()
1101 if (!tc6->waiting_tx_skb && netif_queue_stopped(tc6->netdev)) in oa_tc6_try_spi_transfer()
1102 netif_wake_queue(tc6->netdev); in oa_tc6_try_spi_transfer()
1114 /* This kthread will be waken up if there is a tx skb or mac-phy in oa_tc6_spi_thread_handler()
1117 wait_event_interruptible(tc6->spi_wq, tc6->int_flag || in oa_tc6_spi_thread_handler()
1118 (tc6->waiting_tx_skb && in oa_tc6_spi_thread_handler()
1119 tc6->tx_credits) || in oa_tc6_spi_thread_handler()
1146 tc6->tx_credits = FIELD_GET(BUFFER_STATUS_TX_CREDITS_AVAILABLE, value); in oa_tc6_update_buffer_status_from_register()
1147 tc6->rx_chunks_available = FIELD_GET(BUFFER_STATUS_RX_CHUNKS_AVAILABLE, in oa_tc6_update_buffer_status_from_register()
1157 /* MAC-PHY interrupt can occur for the following reasons. in oa_tc6_macphy_isr()
1158 * - availability of tx credits if it was 0 before and not reported in in oa_tc6_macphy_isr()
1160 * - availability of rx chunks if it was 0 before and not reported in in oa_tc6_macphy_isr()
1162 * - extended status event not reported in the previous rx footer. in oa_tc6_macphy_isr()
1164 tc6->int_flag = true; in oa_tc6_macphy_isr()
1166 wake_up_interruptible(&tc6->spi_wq); in oa_tc6_macphy_isr()
1172 * oa_tc6_zero_align_receive_frame_enable - function to enable zero align
1187 /* Set Zero-Align Receive Frame Enable */ in oa_tc6_zero_align_receive_frame_enable()
1195 * oa_tc6_start_xmit - function for sending the tx skb which consists ethernet
1205 if (tc6->waiting_tx_skb) { in oa_tc6_start_xmit()
1206 netif_stop_queue(tc6->netdev); in oa_tc6_start_xmit()
1212 tc6->netdev->stats.tx_dropped++; in oa_tc6_start_xmit()
1216 spin_lock_bh(&tc6->tx_skb_lock); in oa_tc6_start_xmit()
1217 tc6->waiting_tx_skb = skb; in oa_tc6_start_xmit()
1218 spin_unlock_bh(&tc6->tx_skb_lock); in oa_tc6_start_xmit()
1221 wake_up_interruptible(&tc6->spi_wq); in oa_tc6_start_xmit()
1228 * oa_tc6_init - allocates and initializes oa_tc6 structure.
1232 * Return: pointer reference to the oa_tc6 structure if the MAC-PHY
1240 tc6 = devm_kzalloc(&spi->dev, sizeof(*tc6), GFP_KERNEL); in oa_tc6_init()
1244 tc6->spi = spi; in oa_tc6_init()
1245 tc6->netdev = netdev; in oa_tc6_init()
1246 SET_NETDEV_DEV(netdev, &spi->dev); in oa_tc6_init()
1247 mutex_init(&tc6->spi_ctrl_lock); in oa_tc6_init()
1248 spin_lock_init(&tc6->tx_skb_lock); in oa_tc6_init()
1251 tc6->spi->rt = true; in oa_tc6_init()
1252 spi_setup(tc6->spi); in oa_tc6_init()
1254 tc6->spi_ctrl_tx_buf = devm_kzalloc(&tc6->spi->dev, in oa_tc6_init()
1257 if (!tc6->spi_ctrl_tx_buf) in oa_tc6_init()
1260 tc6->spi_ctrl_rx_buf = devm_kzalloc(&tc6->spi->dev, in oa_tc6_init()
1263 if (!tc6->spi_ctrl_rx_buf) in oa_tc6_init()
1266 tc6->spi_data_tx_buf = devm_kzalloc(&tc6->spi->dev, in oa_tc6_init()
1269 if (!tc6->spi_data_tx_buf) in oa_tc6_init()
1272 tc6->spi_data_rx_buf = devm_kzalloc(&tc6->spi->dev, in oa_tc6_init()
1275 if (!tc6->spi_data_rx_buf) in oa_tc6_init()
1280 dev_err(&tc6->spi->dev, in oa_tc6_init()
1281 "MAC-PHY software reset failed: %d\n", ret); in oa_tc6_init()
1287 dev_err(&tc6->spi->dev, in oa_tc6_init()
1288 "MAC-PHY error interrupts unmask failed: %d\n", ret); in oa_tc6_init()
1294 dev_err(&tc6->spi->dev, in oa_tc6_init()
1301 dev_err(&tc6->spi->dev, "Failed to enable data transfer: %d\n", in oa_tc6_init()
1308 dev_err(&tc6->spi->dev, in oa_tc6_init()
1313 init_waitqueue_head(&tc6->spi_wq); in oa_tc6_init()
1315 tc6->spi_thread = kthread_run(oa_tc6_spi_thread_handler, tc6, in oa_tc6_init()
1316 "oa-tc6-spi-thread"); in oa_tc6_init()
1317 if (IS_ERR(tc6->spi_thread)) { in oa_tc6_init()
1318 dev_err(&tc6->spi->dev, "Failed to create SPI thread\n"); in oa_tc6_init()
1322 sched_set_fifo(tc6->spi_thread); in oa_tc6_init()
1324 ret = devm_request_irq(&tc6->spi->dev, tc6->spi->irq, oa_tc6_macphy_isr, in oa_tc6_init()
1325 IRQF_TRIGGER_FALLING, dev_name(&tc6->spi->dev), in oa_tc6_init()
1328 dev_err(&tc6->spi->dev, "Failed to request macphy isr %d\n", in oa_tc6_init()
1333 /* oa_tc6_sw_reset_macphy() function resets and clears the MAC-PHY reset in oa_tc6_init()
1335 * remain asserted until MAC-PHY receives a data chunk. So performing an in oa_tc6_init()
1339 tc6->int_flag = true; in oa_tc6_init()
1340 wake_up_interruptible(&tc6->spi_wq); in oa_tc6_init()
1345 kthread_stop(tc6->spi_thread); in oa_tc6_init()
1353 * oa_tc6_exit - exit function.
1359 kthread_stop(tc6->spi_thread); in oa_tc6_exit()
1360 dev_kfree_skb_any(tc6->ongoing_tx_skb); in oa_tc6_exit()
1361 dev_kfree_skb_any(tc6->waiting_tx_skb); in oa_tc6_exit()
1362 dev_kfree_skb_any(tc6->rx_skb); in oa_tc6_exit()
1366 MODULE_DESCRIPTION("OPEN Alliance 10BASET1x MAC‑PHY Serial Interface Lib");