From b22da3d8526a935aa31e086e63f60ff3246cb61c Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Sat, 09 Dec 2023 07:24:11 +0000 Subject: [PATCH] add stmac read mac form eeprom --- kernel/drivers/char/ipmi/ipmi_si_intf.c | 214 +++++++++++++++++++++++------------------------------ 1 files changed, 93 insertions(+), 121 deletions(-) diff --git a/kernel/drivers/char/ipmi/ipmi_si_intf.c b/kernel/drivers/char/ipmi/ipmi_si_intf.c index 006d765..5eac94c 100644 --- a/kernel/drivers/char/ipmi/ipmi_si_intf.c +++ b/kernel/drivers/char/ipmi/ipmi_si_intf.c @@ -19,6 +19,8 @@ * and drives the real SMI state machine. */ +#define pr_fmt(fmt) "ipmi_si: " fmt + #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/sched.h> @@ -38,10 +40,9 @@ #include <linux/ipmi.h> #include <linux/ipmi_smi.h> #include "ipmi_si.h" +#include "ipmi_si_sm.h" #include <linux/string.h> #include <linux/ctype.h> - -#define PFX "ipmi_si: " /* Measure times between events in the driver. */ #undef DEBUG_TIMING @@ -71,7 +72,7 @@ static const char * const si_to_str[] = { "invalid", "kcs", "smic", "bt" }; -static int initialized; +static bool initialized; /* * Indexes into stats[] in smi_info below. @@ -232,14 +233,8 @@ /* From the get device id response... */ struct ipmi_device_id device_id; - /* Default driver model device. */ - struct platform_device *pdev; - /* Have we added the device group to the device? */ bool dev_group_added; - - /* Have we added the platform device? */ - bool pdev_registered; /* Counters and things for the proc filesystem. */ atomic_t stats[SI_NUM_STATS]; @@ -272,8 +267,8 @@ { struct timespec64 t; - getnstimeofday64(&t); - pr_debug("**%s: %lld.%9.9ld\n", msg, (long long) t.tv_sec, t.tv_nsec); + ktime_get_ts64(&t); + pr_debug("**%s: %lld.%9.9ld\n", msg, t.tv_sec, t.tv_nsec); } #else #define debug_timestamp(x) @@ -940,42 +935,29 @@ } /* - * Use -1 in the nsec value of the busy waiting timespec to tell that - * we are spinning in kipmid looking for something and not delaying - * between checks + * Use -1 as a special constant to tell that we are spinning in kipmid + * looking for something and not delaying between checks */ -static inline void ipmi_si_set_not_busy(struct timespec64 *ts) -{ - ts->tv_nsec = -1; -} -static inline int ipmi_si_is_busy(struct timespec64 *ts) -{ - return ts->tv_nsec != -1; -} - -static inline int ipmi_thread_busy_wait(enum si_sm_result smi_result, - const struct smi_info *smi_info, - struct timespec64 *busy_until) +#define IPMI_TIME_NOT_BUSY ns_to_ktime(-1ull) +static inline bool ipmi_thread_busy_wait(enum si_sm_result smi_result, + const struct smi_info *smi_info, + ktime_t *busy_until) { unsigned int max_busy_us = 0; if (smi_info->si_num < num_max_busy_us) max_busy_us = kipmid_max_busy_us[smi_info->si_num]; if (max_busy_us == 0 || smi_result != SI_SM_CALL_WITH_DELAY) - ipmi_si_set_not_busy(busy_until); - else if (!ipmi_si_is_busy(busy_until)) { - getnstimeofday64(busy_until); - timespec64_add_ns(busy_until, max_busy_us*NSEC_PER_USEC); + *busy_until = IPMI_TIME_NOT_BUSY; + else if (*busy_until == IPMI_TIME_NOT_BUSY) { + *busy_until = ktime_get() + max_busy_us * NSEC_PER_USEC; } else { - struct timespec64 now; - - getnstimeofday64(&now); - if (unlikely(timespec64_compare(&now, busy_until) > 0)) { - ipmi_si_set_not_busy(busy_until); - return 0; + if (unlikely(ktime_get() > *busy_until)) { + *busy_until = IPMI_TIME_NOT_BUSY; + return false; } } - return 1; + return true; } @@ -986,16 +968,15 @@ * that are not BT and do not have interrupts. It starts spinning * when an operation is complete or until max_busy tells it to stop * (if that is enabled). See the paragraph on kimid_max_busy_us in - * Documentation/IPMI.txt for details. + * Documentation/driver-api/ipmi.rst for details. */ static int ipmi_thread(void *data) { struct smi_info *smi_info = data; unsigned long flags; enum si_sm_result smi_result; - struct timespec64 busy_until; + ktime_t busy_until = IPMI_TIME_NOT_BUSY; - ipmi_si_set_not_busy(&busy_until); set_user_nice(current, MAX_NICE); while (!kthread_should_stop()) { int busy_wait; @@ -1073,10 +1054,13 @@ atomic_set(&smi_info->req_events, 1); } -static void set_need_watch(void *send_info, bool enable) +static void set_need_watch(void *send_info, unsigned int watch_mask) { struct smi_info *smi_info = send_info; unsigned long flags; + int enable; + + enable = !!watch_mask; atomic_set(&smi_info->need_watch, enable); spin_lock_irqsave(&smi_info->si_lock, flags); @@ -1283,12 +1267,12 @@ rv = request_irq(io->irq, ipmi_si_irq_handler, IRQF_SHARED, - DEVICE_NAME, + SI_DEVICE_NAME, io->irq_handler_data); if (rv) { dev_warn(io->dev, "%s unable to claim interrupt %d," " running polled\n", - DEVICE_NAME, io->irq); + SI_DEVICE_NAME, io->irq); io->irq = 0; } else { io->irq_cleanup = std_irq_cleanup; @@ -1332,6 +1316,7 @@ unsigned char *resp; unsigned long resp_len; int rv = 0; + unsigned int retry_count = 0; resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL); if (!resp) @@ -1343,6 +1328,8 @@ */ msg[0] = IPMI_NETFN_APP_REQUEST << 2; msg[1] = IPMI_GET_DEVICE_ID_CMD; + +retry: smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2); rv = wait_for_msg_done(smi_info); @@ -1355,6 +1342,20 @@ /* Check and record info from the get device id, in case we need it. */ rv = ipmi_demangle_device_id(resp[0] >> 2, resp[1], resp + 2, resp_len - 2, &smi_info->device_id); + if (rv) { + /* record completion code */ + unsigned char cc = *(resp + 2); + + if ((cc == IPMI_DEVICE_IN_FW_UPDATE_ERR + || cc == IPMI_DEVICE_IN_INIT_ERR + || cc == IPMI_NOT_IN_MY_STATE_ERR) + && ++retry_count <= GET_DEVICE_ID_MAX_RETRY) { + dev_warn(smi_info->io.dev, + "BMC returned 0x%2.2x, retry get bmc device id\n", + cc); + goto retry; + } + } out: kfree(resp); @@ -1544,7 +1545,7 @@ rv = wait_for_msg_done(smi_info); if (rv) { - pr_warn(PFX "Error getting response from get global enables command, the event buffer is not enabled.\n"); + pr_warn("Error getting response from get global enables command, the event buffer is not enabled\n"); goto out; } @@ -1555,7 +1556,7 @@ resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 || resp[1] != IPMI_GET_BMC_GLOBAL_ENABLES_CMD || resp[2] != 0) { - pr_warn(PFX "Invalid return from get global enables command, cannot enable the event buffer.\n"); + pr_warn("Invalid return from get global enables command, cannot enable the event buffer\n"); rv = -EINVAL; goto out; } @@ -1573,7 +1574,7 @@ rv = wait_for_msg_done(smi_info); if (rv) { - pr_warn(PFX "Error getting response from set global, enables command, the event buffer is not enabled.\n"); + pr_warn("Error getting response from set global, enables command, the event buffer is not enabled\n"); goto out; } @@ -1583,7 +1584,7 @@ if (resp_len < 3 || resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 || resp[1] != IPMI_SET_BMC_GLOBAL_ENABLES_CMD) { - pr_warn(PFX "Invalid return from get global, enables command, not enable the event buffer.\n"); + pr_warn("Invalid return from get global, enables command, not enable the event buffer\n"); rv = -EINVAL; goto out; } @@ -1603,37 +1604,37 @@ } #define IPMI_SI_ATTR(name) \ -static ssize_t ipmi_##name##_show(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ +static ssize_t name##_show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ { \ struct smi_info *smi_info = dev_get_drvdata(dev); \ \ return snprintf(buf, 10, "%u\n", smi_get_stat(smi_info, name)); \ } \ -static DEVICE_ATTR(name, S_IRUGO, ipmi_##name##_show, NULL) +static DEVICE_ATTR(name, 0444, name##_show, NULL) -static ssize_t ipmi_type_show(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t type_show(struct device *dev, + struct device_attribute *attr, + char *buf) { struct smi_info *smi_info = dev_get_drvdata(dev); return snprintf(buf, 10, "%s\n", si_to_str[smi_info->io.si_type]); } -static DEVICE_ATTR(type, S_IRUGO, ipmi_type_show, NULL); +static DEVICE_ATTR(type, 0444, type_show, NULL); -static ssize_t ipmi_interrupts_enabled_show(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t interrupts_enabled_show(struct device *dev, + struct device_attribute *attr, + char *buf) { struct smi_info *smi_info = dev_get_drvdata(dev); int enabled = smi_info->io.irq && !smi_info->interrupt_disabled; return snprintf(buf, 10, "%d\n", enabled); } -static DEVICE_ATTR(interrupts_enabled, S_IRUGO, - ipmi_interrupts_enabled_show, NULL); +static DEVICE_ATTR(interrupts_enabled, 0444, + interrupts_enabled_show, NULL); IPMI_SI_ATTR(short_timeouts); IPMI_SI_ATTR(long_timeouts); @@ -1647,16 +1648,16 @@ IPMI_SI_ATTR(watchdog_pretimeouts); IPMI_SI_ATTR(incoming_messages); -static ssize_t ipmi_params_show(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t params_show(struct device *dev, + struct device_attribute *attr, + char *buf) { struct smi_info *smi_info = dev_get_drvdata(dev); return snprintf(buf, 200, "%s,%s,0x%lx,rsp=%d,rsi=%d,rsh=%d,irq=%d,ipmb=%d\n", si_to_str[smi_info->io.si_type], - addr_space_to_str[smi_info->io.addr_type], + addr_space_to_str[smi_info->io.addr_space], smi_info->io.addr_data, smi_info->io.regspacing, smi_info->io.regsize, @@ -1664,7 +1665,7 @@ smi_info->io.irq, smi_info->io.slave_addr); } -static DEVICE_ATTR(params, S_IRUGO, ipmi_params_show, NULL); +static DEVICE_ATTR(params, 0444, params_show, NULL); static struct attribute *ipmi_si_dev_attrs[] = { &dev_attr_type.attr, @@ -1845,8 +1846,7 @@ } smi_info->timer_can_start = false; - if (smi_info->timer_running) - del_timer_sync(&smi_info->si_timer); + del_timer_sync(&smi_info->si_timer); } static struct smi_info *find_dup_si(struct smi_info *info) @@ -1854,7 +1854,7 @@ struct smi_info *e; list_for_each_entry(e, &smi_infos, link) { - if (e->io.addr_type != info->io.addr_type) + if (e->io.addr_space != info->io.addr_space) continue; if (e->io.addr_data == info->io.addr_data) { /* @@ -1881,17 +1881,17 @@ * address, they presumably want us to use it and not what is * in the firmware. */ - if (io->addr_source != SI_HARDCODED && - ipmi_si_hardcode_match(io->addr_type, io->addr_data)) { + if (io->addr_source != SI_HARDCODED && io->addr_source != SI_HOTMOD && + ipmi_si_hardcode_match(io->addr_space, io->addr_data)) { dev_info(io->dev, "Hard-coded device at this address already exists"); return -ENODEV; } if (!io->io_setup) { - if (io->addr_type == IPMI_IO_ADDR_SPACE) { + if (io->addr_space == IPMI_IO_ADDR_SPACE) { io->io_setup = ipmi_si_port_setup; - } else if (io->addr_type == IPMI_MEM_ADDR_SPACE) { + } else if (io->addr_space == IPMI_MEM_ADDR_SPACE) { io->io_setup = ipmi_si_mem_setup; } else { return -EINVAL; @@ -1926,7 +1926,7 @@ } } - pr_info(PFX "Adding %s-specified %s state machine\n", + pr_info("Adding %s-specified %s state machine\n", ipmi_addr_src_to_str(new_smi->io.addr_source), si_to_str[new_smi->io.si_type]); @@ -1948,12 +1948,11 @@ { int rv = 0; int i; - char *init_name = NULL; - pr_info(PFX "Trying %s-specified %s state machine at %s address 0x%lx, slave address 0x%x, irq %d\n", + pr_info("Trying %s-specified %s state machine at %s address 0x%lx, slave address 0x%x, irq %d\n", ipmi_addr_src_to_str(new_smi->io.addr_source), si_to_str[new_smi->io.si_type], - addr_space_to_str[new_smi->io.addr_type], + addr_space_to_str[new_smi->io.addr_space], new_smi->io.addr_data, new_smi->io.slave_addr, new_smi->io.irq); @@ -1980,24 +1979,9 @@ /* Do this early so it's available for logs. */ if (!new_smi->io.dev) { - init_name = kasprintf(GFP_KERNEL, "ipmi_si.%d", - new_smi->si_num); - - /* - * If we don't already have a device from something - * else (like PCI), then register a new one. - */ - new_smi->pdev = platform_device_alloc("ipmi_si", - new_smi->si_num); - if (!new_smi->pdev) { - pr_err(PFX "Unable to allocate platform device\n"); - rv = -ENOMEM; - goto out_err; - } - new_smi->io.dev = &new_smi->pdev->dev; - new_smi->io.dev->driver = &ipmi_platform_driver.driver; - /* Nulled by device_add() */ - new_smi->io.dev->init_name = init_name; + pr_err("IPMI interface added with no device\n"); + rv = -EIO; + goto out_err; } /* Allocate the state machine's data and initialize it. */ @@ -2070,17 +2054,6 @@ atomic_set(&new_smi->req_events, 1); } - if (new_smi->pdev && !new_smi->pdev_registered) { - rv = platform_device_add(new_smi->pdev); - if (rv) { - dev_err(new_smi->io.dev, - "Unable to register system interface device: %d\n", - rv); - goto out_err; - } - new_smi->pdev_registered = true; - } - dev_set_drvdata(new_smi->io.dev, new_smi); rv = device_add_group(new_smi->io.dev, &ipmi_si_dev_attr_group); if (rv) { @@ -2116,7 +2089,6 @@ new_smi->io.io_cleanup = NULL; } - kfree(init_name); return rv; } @@ -2129,7 +2101,8 @@ return 0; ipmi_hardcode_init(); - pr_info("IPMI System Interface driver.\n"); + + pr_info("IPMI System Interface driver\n"); ipmi_si_platform_init(); @@ -2168,7 +2141,7 @@ } skip_fallback_noirq: - initialized = 1; + initialized = true; mutex_unlock(&smi_infos_lock); if (type) @@ -2178,7 +2151,7 @@ if (unload_when_empty && list_empty(&smi_infos)) { mutex_unlock(&smi_infos_lock); cleanup_ipmi_si(); - pr_warn(PFX "Unable to find any System Interface(s)\n"); + pr_warn("Unable to find any System Interface(s)\n"); return -ENODEV; } else { mutex_unlock(&smi_infos_lock); @@ -2214,7 +2187,7 @@ * handlers might have been running before we freed the * interrupt. */ - synchronize_sched(); + synchronize_rcu(); /* * Timeouts are stopped, now make sure the interrupts are off @@ -2263,13 +2236,6 @@ if (smi_info->intf) ipmi_unregister_smi(smi_info->intf); - if (smi_info->pdev) { - if (smi_info->pdev_registered) - platform_device_unregister(smi_info->pdev); - else - platform_device_put(smi_info->pdev); - } - kfree(smi_info); } @@ -2291,22 +2257,27 @@ return rv; } -void ipmi_si_remove_by_data(int addr_space, enum si_type si_type, - unsigned long addr) +struct device *ipmi_si_remove_by_data(int addr_space, enum si_type si_type, + unsigned long addr) { /* remove */ struct smi_info *e, *tmp_e; + struct device *dev = NULL; mutex_lock(&smi_infos_lock); list_for_each_entry_safe(e, tmp_e, &smi_infos, link) { - if (e->io.addr_type != addr_space) + if (e->io.addr_space != addr_space) continue; if (e->io.si_type != si_type) continue; - if (e->io.addr_data == addr) + if (e->io.addr_data == addr) { + dev = get_device(e->io.dev); cleanup_one_si(e); + } } mutex_unlock(&smi_infos_lock); + + return dev; } static void cleanup_ipmi_si(void) @@ -2328,6 +2299,7 @@ mutex_unlock(&smi_infos_lock); ipmi_si_hardcode_exit(); + ipmi_si_hotmod_exit(); } module_exit(cleanup_ipmi_si); -- Gitblit v1.6.2