drivers/net/ethernet/sunplus/spl2sw_driver.c

Source file repositories/reference/linux-study-clean/drivers/net/ethernet/sunplus/spl2sw_driver.c

File Facts

System
Linux kernel
Corpus path
drivers/net/ethernet/sunplus/spl2sw_driver.c
Extension
.c
Size
13613 bytes
Lines
564
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

static const struct net_device_ops netdev_ops = {
	.ndo_open = spl2sw_ethernet_open,
	.ndo_stop = spl2sw_ethernet_stop,
	.ndo_start_xmit = spl2sw_ethernet_start_xmit,
	.ndo_set_rx_mode = spl2sw_ethernet_set_rx_mode,
	.ndo_set_mac_address = spl2sw_ethernet_set_mac_address,
	.ndo_eth_ioctl = phy_do_ioctl,
	.ndo_tx_timeout = spl2sw_ethernet_tx_timeout,
};

static void spl2sw_check_mac_vendor_id_and_convert(u8 *mac_addr)
{
	/* Byte order of MAC address of some samples are reversed.
	 * Check vendor id and convert byte order if it is wrong.
	 * OUI of Sunplus: fc:4b:bc
	 */
	if (mac_addr[5] == 0xfc && mac_addr[4] == 0x4b && mac_addr[3] == 0xbc &&
	    (mac_addr[0] != 0xfc || mac_addr[1] != 0x4b || mac_addr[2] != 0xbc)) {

		swap(mac_addr[0], mac_addr[5]);
		swap(mac_addr[1], mac_addr[4]);
		swap(mac_addr[2], mac_addr[3]);
	}
}

static int spl2sw_nvmem_get_mac_address(struct device *dev, struct device_node *np,
					void *addrbuf)
{
	struct nvmem_cell *cell;
	ssize_t len;
	u8 *mac;

	/* Get nvmem cell of mac-address from dts. */
	cell = of_nvmem_cell_get(np, "mac-address");
	if (IS_ERR(cell))
		return PTR_ERR(cell);

	/* Read mac address from nvmem cell. */
	mac = nvmem_cell_read(cell, &len);
	nvmem_cell_put(cell);
	if (IS_ERR(mac))
		return PTR_ERR(mac);

	if (len != ETH_ALEN) {
		kfree(mac);
		dev_info(dev, "Invalid length of mac address in nvmem!\n");
		return -EINVAL;
	}

	/* Byte order of some samples are reversed.
	 * Convert byte order here.
	 */
	spl2sw_check_mac_vendor_id_and_convert(mac);

	/* Check if mac address is valid */
	if (!is_valid_ether_addr(mac)) {
		dev_info(dev, "Invalid mac address in nvmem (%pM)!\n", mac);
		kfree(mac);
		return -EINVAL;
	}

	ether_addr_copy(addrbuf, mac);
	kfree(mac);
	return 0;
}

static u32 spl2sw_init_netdev(struct platform_device *pdev, u8 *mac_addr,
			      struct net_device **r_ndev)
{
	struct net_device *ndev;
	struct spl2sw_mac *mac;
	int ret;

	/* Allocate the devices, and also allocate spl2sw_mac,
	 * we can get it by netdev_priv().
	 */
	ndev = devm_alloc_etherdev(&pdev->dev, sizeof(*mac));
	if (!ndev) {
		*r_ndev = NULL;
		return -ENOMEM;
	}
	SET_NETDEV_DEV(ndev, &pdev->dev);
	ndev->netdev_ops = &netdev_ops;
	mac = netdev_priv(ndev);
	mac->ndev = ndev;
	ether_addr_copy(mac->mac_addr, mac_addr);

	eth_hw_addr_set(ndev, mac_addr);
	dev_info(&pdev->dev, "Ethernet (MAC) address = %pM\n", mac_addr);

Annotation

Implementation Notes