162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * INET An implementation of the TCP/IP protocol suite for the LINUX 462306a36Sopenharmony_ci * operating system. INET is implemented using the BSD Socket 562306a36Sopenharmony_ci * interface as the means of communication with the user level. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Holds initial configuration information for devices. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Version: @(#)Space.c 1.0.7 08/12/93 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Authors: Ross Biro 1262306a36Sopenharmony_ci * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> 1362306a36Sopenharmony_ci * Donald J. Becker, <becker@scyld.com> 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * Changelog: 1662306a36Sopenharmony_ci * Stephen Hemminger (09/2003) 1762306a36Sopenharmony_ci * - get rid of pre-linked dev list, dynamic device allocation 1862306a36Sopenharmony_ci * Paul Gortmaker (03/2002) 1962306a36Sopenharmony_ci * - struct init cleanup, enable multiple ISA autoprobes. 2062306a36Sopenharmony_ci * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 09/1999 2162306a36Sopenharmony_ci * - fix sbni: s/device/net_device/ 2262306a36Sopenharmony_ci * Paul Gortmaker (06/98): 2362306a36Sopenharmony_ci * - sort probes in a sane way, make sure all (safe) probes 2462306a36Sopenharmony_ci * get run once & failed autoprobes don't autoprobe again. 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_ci#include <linux/netdevice.h> 2762306a36Sopenharmony_ci#include <linux/etherdevice.h> 2862306a36Sopenharmony_ci#include <linux/errno.h> 2962306a36Sopenharmony_ci#include <linux/init.h> 3062306a36Sopenharmony_ci#include <linux/netlink.h> 3162306a36Sopenharmony_ci#include <net/Space.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* 3462306a36Sopenharmony_ci * This structure holds boot-time configured netdevice settings. They 3562306a36Sopenharmony_ci * are then used in the device probing. 3662306a36Sopenharmony_ci */ 3762306a36Sopenharmony_cistruct netdev_boot_setup { 3862306a36Sopenharmony_ci char name[IFNAMSIZ]; 3962306a36Sopenharmony_ci struct ifmap map; 4062306a36Sopenharmony_ci}; 4162306a36Sopenharmony_ci#define NETDEV_BOOT_SETUP_MAX 8 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/****************************************************************************** 4562306a36Sopenharmony_ci * 4662306a36Sopenharmony_ci * Device Boot-time Settings Routines 4762306a36Sopenharmony_ci * 4862306a36Sopenharmony_ci ******************************************************************************/ 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci/* Boot time configuration table */ 5162306a36Sopenharmony_cistatic struct netdev_boot_setup dev_boot_setup[NETDEV_BOOT_SETUP_MAX]; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/** 5462306a36Sopenharmony_ci * netdev_boot_setup_add - add new setup entry 5562306a36Sopenharmony_ci * @name: name of the device 5662306a36Sopenharmony_ci * @map: configured settings for the device 5762306a36Sopenharmony_ci * 5862306a36Sopenharmony_ci * Adds new setup entry to the dev_boot_setup list. The function 5962306a36Sopenharmony_ci * returns 0 on error and 1 on success. This is a generic routine to 6062306a36Sopenharmony_ci * all netdevices. 6162306a36Sopenharmony_ci */ 6262306a36Sopenharmony_cistatic int netdev_boot_setup_add(char *name, struct ifmap *map) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci struct netdev_boot_setup *s; 6562306a36Sopenharmony_ci int i; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci s = dev_boot_setup; 6862306a36Sopenharmony_ci for (i = 0; i < NETDEV_BOOT_SETUP_MAX; i++) { 6962306a36Sopenharmony_ci if (s[i].name[0] == '\0' || s[i].name[0] == ' ') { 7062306a36Sopenharmony_ci memset(s[i].name, 0, sizeof(s[i].name)); 7162306a36Sopenharmony_ci strscpy(s[i].name, name, IFNAMSIZ); 7262306a36Sopenharmony_ci memcpy(&s[i].map, map, sizeof(s[i].map)); 7362306a36Sopenharmony_ci break; 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci } 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci return i >= NETDEV_BOOT_SETUP_MAX ? 0 : 1; 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci/** 8162306a36Sopenharmony_ci * netdev_boot_setup_check - check boot time settings 8262306a36Sopenharmony_ci * @dev: the netdevice 8362306a36Sopenharmony_ci * 8462306a36Sopenharmony_ci * Check boot time settings for the device. 8562306a36Sopenharmony_ci * The found settings are set for the device to be used 8662306a36Sopenharmony_ci * later in the device probing. 8762306a36Sopenharmony_ci * Returns 0 if no settings found, 1 if they are. 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_ciint netdev_boot_setup_check(struct net_device *dev) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci struct netdev_boot_setup *s = dev_boot_setup; 9262306a36Sopenharmony_ci int i; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci for (i = 0; i < NETDEV_BOOT_SETUP_MAX; i++) { 9562306a36Sopenharmony_ci if (s[i].name[0] != '\0' && s[i].name[0] != ' ' && 9662306a36Sopenharmony_ci !strcmp(dev->name, s[i].name)) { 9762306a36Sopenharmony_ci dev->irq = s[i].map.irq; 9862306a36Sopenharmony_ci dev->base_addr = s[i].map.base_addr; 9962306a36Sopenharmony_ci dev->mem_start = s[i].map.mem_start; 10062306a36Sopenharmony_ci dev->mem_end = s[i].map.mem_end; 10162306a36Sopenharmony_ci return 1; 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci return 0; 10562306a36Sopenharmony_ci} 10662306a36Sopenharmony_ciEXPORT_SYMBOL(netdev_boot_setup_check); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci/** 10962306a36Sopenharmony_ci * netdev_boot_base - get address from boot time settings 11062306a36Sopenharmony_ci * @prefix: prefix for network device 11162306a36Sopenharmony_ci * @unit: id for network device 11262306a36Sopenharmony_ci * 11362306a36Sopenharmony_ci * Check boot time settings for the base address of device. 11462306a36Sopenharmony_ci * The found settings are set for the device to be used 11562306a36Sopenharmony_ci * later in the device probing. 11662306a36Sopenharmony_ci * Returns 0 if no settings found. 11762306a36Sopenharmony_ci */ 11862306a36Sopenharmony_cistatic unsigned long netdev_boot_base(const char *prefix, int unit) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci const struct netdev_boot_setup *s = dev_boot_setup; 12162306a36Sopenharmony_ci char name[IFNAMSIZ]; 12262306a36Sopenharmony_ci int i; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci sprintf(name, "%s%d", prefix, unit); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci /* 12762306a36Sopenharmony_ci * If device already registered then return base of 1 12862306a36Sopenharmony_ci * to indicate not to probe for this interface 12962306a36Sopenharmony_ci */ 13062306a36Sopenharmony_ci if (__dev_get_by_name(&init_net, name)) 13162306a36Sopenharmony_ci return 1; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci for (i = 0; i < NETDEV_BOOT_SETUP_MAX; i++) 13462306a36Sopenharmony_ci if (!strcmp(name, s[i].name)) 13562306a36Sopenharmony_ci return s[i].map.base_addr; 13662306a36Sopenharmony_ci return 0; 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/* 14062306a36Sopenharmony_ci * Saves at boot time configured settings for any netdevice. 14162306a36Sopenharmony_ci */ 14262306a36Sopenharmony_cistatic int __init netdev_boot_setup(char *str) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci int ints[5]; 14562306a36Sopenharmony_ci struct ifmap map; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci str = get_options(str, ARRAY_SIZE(ints), ints); 14862306a36Sopenharmony_ci if (!str || !*str) 14962306a36Sopenharmony_ci return 0; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci /* Save settings */ 15262306a36Sopenharmony_ci memset(&map, 0, sizeof(map)); 15362306a36Sopenharmony_ci if (ints[0] > 0) 15462306a36Sopenharmony_ci map.irq = ints[1]; 15562306a36Sopenharmony_ci if (ints[0] > 1) 15662306a36Sopenharmony_ci map.base_addr = ints[2]; 15762306a36Sopenharmony_ci if (ints[0] > 2) 15862306a36Sopenharmony_ci map.mem_start = ints[3]; 15962306a36Sopenharmony_ci if (ints[0] > 3) 16062306a36Sopenharmony_ci map.mem_end = ints[4]; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci /* Add new entry to the list */ 16362306a36Sopenharmony_ci return netdev_boot_setup_add(str, &map); 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci__setup("netdev=", netdev_boot_setup); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic int __init ether_boot_setup(char *str) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci return netdev_boot_setup(str); 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci__setup("ether=", ether_boot_setup); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci/* A unified ethernet device probe. This is the easiest way to have every 17662306a36Sopenharmony_ci * ethernet adaptor have the name "eth[0123...]". 17762306a36Sopenharmony_ci */ 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistruct devprobe2 { 18062306a36Sopenharmony_ci struct net_device *(*probe)(int unit); 18162306a36Sopenharmony_ci int status; /* non-zero if autoprobe has failed */ 18262306a36Sopenharmony_ci}; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistatic int __init probe_list2(int unit, struct devprobe2 *p, int autoprobe) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci struct net_device *dev; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci for (; p->probe; p++) { 18962306a36Sopenharmony_ci if (autoprobe && p->status) 19062306a36Sopenharmony_ci continue; 19162306a36Sopenharmony_ci dev = p->probe(unit); 19262306a36Sopenharmony_ci if (!IS_ERR(dev)) 19362306a36Sopenharmony_ci return 0; 19462306a36Sopenharmony_ci if (autoprobe) 19562306a36Sopenharmony_ci p->status = PTR_ERR(dev); 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci return -ENODEV; 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci/* ISA probes that touch addresses < 0x400 (including those that also 20162306a36Sopenharmony_ci * look for EISA/PCI cards in addition to ISA cards). 20262306a36Sopenharmony_ci */ 20362306a36Sopenharmony_cistatic struct devprobe2 isa_probes[] __initdata = { 20462306a36Sopenharmony_ci#ifdef CONFIG_3C515 20562306a36Sopenharmony_ci {tc515_probe, 0}, 20662306a36Sopenharmony_ci#endif 20762306a36Sopenharmony_ci#ifdef CONFIG_ULTRA 20862306a36Sopenharmony_ci {ultra_probe, 0}, 20962306a36Sopenharmony_ci#endif 21062306a36Sopenharmony_ci#ifdef CONFIG_WD80x3 21162306a36Sopenharmony_ci {wd_probe, 0}, 21262306a36Sopenharmony_ci#endif 21362306a36Sopenharmony_ci#if defined(CONFIG_NE2000) /* ISA (use ne2k-pci for PCI cards) */ 21462306a36Sopenharmony_ci {ne_probe, 0}, 21562306a36Sopenharmony_ci#endif 21662306a36Sopenharmony_ci#ifdef CONFIG_LANCE /* ISA/VLB (use pcnet32 for PCI cards) */ 21762306a36Sopenharmony_ci {lance_probe, 0}, 21862306a36Sopenharmony_ci#endif 21962306a36Sopenharmony_ci#ifdef CONFIG_SMC9194 22062306a36Sopenharmony_ci {smc_init, 0}, 22162306a36Sopenharmony_ci#endif 22262306a36Sopenharmony_ci#ifdef CONFIG_CS89x0_ISA 22362306a36Sopenharmony_ci {cs89x0_probe, 0}, 22462306a36Sopenharmony_ci#endif 22562306a36Sopenharmony_ci {NULL, 0}, 22662306a36Sopenharmony_ci}; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci/* Unified ethernet device probe, segmented per architecture and 22962306a36Sopenharmony_ci * per bus interface. This drives the legacy devices only for now. 23062306a36Sopenharmony_ci */ 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic void __init ethif_probe2(int unit) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci unsigned long base_addr = netdev_boot_base("eth", unit); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci if (base_addr == 1) 23762306a36Sopenharmony_ci return; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci probe_list2(unit, isa_probes, base_addr == 0); 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci/* Statically configured drivers -- order matters here. */ 24362306a36Sopenharmony_cistatic int __init net_olddevs_init(void) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci int num; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci for (num = 0; num < 8; ++num) 24862306a36Sopenharmony_ci ethif_probe2(num); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci#ifdef CONFIG_COPS 25162306a36Sopenharmony_ci cops_probe(0); 25262306a36Sopenharmony_ci cops_probe(1); 25362306a36Sopenharmony_ci cops_probe(2); 25462306a36Sopenharmony_ci#endif 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci return 0; 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cidevice_initcall(net_olddevs_init); 260