Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only 2 : : /* 3 : : * OF helpers for network devices. 4 : : * 5 : : * Initially copied out of arch/powerpc/kernel/prom_parse.c 6 : : */ 7 : : #include <linux/etherdevice.h> 8 : : #include <linux/kernel.h> 9 : : #include <linux/of_net.h> 10 : : #include <linux/of_platform.h> 11 : : #include <linux/phy.h> 12 : : #include <linux/export.h> 13 : : #include <linux/device.h> 14 : : 15 : : /** 16 : : * of_get_phy_mode - Get phy mode for given device_node 17 : : * @np: Pointer to the given device_node 18 : : * 19 : : * The function gets phy interface string from property 'phy-mode' or 20 : : * 'phy-connection-type', and return its index in phy_modes table, or errno in 21 : : * error case. 22 : : */ 23 : 0 : int of_get_phy_mode(struct device_node *np) 24 : : { 25 : : const char *pm; 26 : : int err, i; 27 : : 28 : 0 : err = of_property_read_string(np, "phy-mode", &pm); 29 [ # # ]: 0 : if (err < 0) 30 : 0 : err = of_property_read_string(np, "phy-connection-type", &pm); 31 [ # # ]: 0 : if (err < 0) 32 : : return err; 33 : : 34 [ # # ]: 0 : for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++) 35 [ # # # # ]: 0 : if (!strcasecmp(pm, phy_modes(i))) 36 : 0 : return i; 37 : : 38 : : return -ENODEV; 39 : : } 40 : : EXPORT_SYMBOL_GPL(of_get_phy_mode); 41 : : 42 : 0 : static const void *of_get_mac_addr(struct device_node *np, const char *name) 43 : : { 44 : 0 : struct property *pp = of_find_property(np, name, NULL); 45 : : 46 [ # # # # : 0 : if (pp && pp->length == ETH_ALEN && is_valid_ether_addr(pp->value)) # # ] 47 : 0 : return pp->value; 48 : : return NULL; 49 : : } 50 : : 51 : 0 : static const void *of_get_mac_addr_nvmem(struct device_node *np) 52 : : { 53 : : int ret; 54 : : const void *mac; 55 : : u8 nvmem_mac[ETH_ALEN]; 56 : 0 : struct platform_device *pdev = of_find_device_by_node(np); 57 : : 58 [ # # ]: 0 : if (!pdev) 59 : : return ERR_PTR(-ENODEV); 60 : : 61 : 0 : ret = nvmem_get_mac_address(&pdev->dev, &nvmem_mac); 62 [ # # ]: 0 : if (ret) { 63 : 0 : put_device(&pdev->dev); 64 : 0 : return ERR_PTR(ret); 65 : : } 66 : : 67 : 0 : mac = devm_kmemdup(&pdev->dev, nvmem_mac, ETH_ALEN, GFP_KERNEL); 68 : 0 : put_device(&pdev->dev); 69 [ # # ]: 0 : if (!mac) 70 : : return ERR_PTR(-ENOMEM); 71 : : 72 : 0 : return mac; 73 : : } 74 : : 75 : : /** 76 : : * Search the device tree for the best MAC address to use. 'mac-address' is 77 : : * checked first, because that is supposed to contain to "most recent" MAC 78 : : * address. If that isn't set, then 'local-mac-address' is checked next, 79 : : * because that is the default address. If that isn't set, then the obsolete 80 : : * 'address' is checked, just in case we're using an old device tree. If any 81 : : * of the above isn't set, then try to get MAC address from nvmem cell named 82 : : * 'mac-address'. 83 : : * 84 : : * Note that the 'address' property is supposed to contain a virtual address of 85 : : * the register set, but some DTS files have redefined that property to be the 86 : : * MAC address. 87 : : * 88 : : * All-zero MAC addresses are rejected, because those could be properties that 89 : : * exist in the device tree, but were not set by U-Boot. For example, the 90 : : * DTS could define 'mac-address' and 'local-mac-address', with zero MAC 91 : : * addresses. Some older U-Boots only initialized 'local-mac-address'. In 92 : : * this case, the real MAC is in 'local-mac-address', and 'mac-address' exists 93 : : * but is all zeros. 94 : : * 95 : : * Return: Will be a valid pointer on success and ERR_PTR in case of error. 96 : : */ 97 : 0 : const void *of_get_mac_address(struct device_node *np) 98 : : { 99 : : const void *addr; 100 : : 101 : 0 : addr = of_get_mac_addr(np, "mac-address"); 102 [ # # ]: 0 : if (addr) 103 : : return addr; 104 : : 105 : 0 : addr = of_get_mac_addr(np, "local-mac-address"); 106 [ # # ]: 0 : if (addr) 107 : : return addr; 108 : : 109 : 0 : addr = of_get_mac_addr(np, "address"); 110 [ # # ]: 0 : if (addr) 111 : : return addr; 112 : : 113 : 0 : return of_get_mac_addr_nvmem(np); 114 : : } 115 : : EXPORT_SYMBOL(of_get_mac_address);