From 96b7988f12c163e1a9cc6a2597341ecf3dafb007 Mon Sep 17 00:00:00 2001 From: Alexander Motin Date: Tue, 17 May 2011 22:07:45 +0000 Subject: [PATCH 1/3] Add support for "LED" enclosure management messages, defined by the AHCI. When supported by hardware, this allows to control per-port activity, locate and fault LEDs via the led(4) API for localization and status reporting purposes. Supporting AHCI controllers may transmit that information to the backplane controllers via SGPIO interface. Backplane controllers interpret received statuses in some way (IBPI standard) to report them using present indicators. --- share/man/man4/ahci.4 | 20 +++++++++++- sys/dev/ahci/ahci.c | 71 +++++++++++++++++++++++++++++++++++++++++++ sys/dev/ahci/ahci.h | 12 ++++++++ 3 files changed, 102 insertions(+), 1 deletion(-) diff --git a/share/man/man4/ahci.4 b/share/man/man4/ahci.4 index 144d64b831a..68aea35b667 100644 --- a/share/man/man4/ahci.4 +++ b/share/man/man4/ahci.4 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd January 28, 2010 +.Dd May 17, 2011 .Dt AHCI 4 .Os .Sh NAME @@ -121,6 +121,15 @@ hardware command queues (up to 32 commands per port), Native Command Queuing, SATA interface Power Management, device hot-plug and Message Signaled Interrupts. .Pp +Driver supports "LED" enclosure management messages, defined by the AHCI. +When supported by hardware, it allows to control per-port activity, locate +and fault LEDs via the +.Xr led 4 +API for localization and status reporting purposes. +Supporting AHCI controllers may transmit that information to the backplane +controllers via SGPIO interface. Backplane controllers interpret received +statuses in some way (IBPI standard) to report them using present indicators. +.Pp AHCI hardware is also supported by ataahci driver from .Xr ata 4 subsystem. @@ -135,6 +144,15 @@ subclass 6 (SATA) and programming interface 1 (AHCI). Also, in cooperation with atamarvell and atajmicron drivers of ata(4), it supports AHCI part of legacy-PATA + AHCI-SATA combined controllers, such as JMicron JMB36x and Marvell 88SX61xx. +.Sh FILES +.Bl -tag -width /dev/led/ahcich*.locate +.It Pa /dev/led/ahcich*.act +activity LED device nodes +.It Pa /dev/led/ahcich*.fault +fault LED device nodes +.It Pa /dev/led/ahcich*.locate +locate LED device nodes +.El .Sh SEE ALSO .Xr ada 4 , .Xr ata 4 , diff --git a/sys/dev/ahci/ahci.c b/sys/dev/ahci/ahci.c index 6ff8f9d72ef..2a064923cf3 100644 --- a/sys/dev/ahci/ahci.c +++ b/sys/dev/ahci/ahci.c @@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include "ahci.h" @@ -68,6 +69,7 @@ static int ahci_ch_resume(device_t dev); static void ahci_ch_pm(void *arg); static void ahci_ch_intr_locked(void *data); static void ahci_ch_intr(void *data); +static void ahci_ch_led(void *priv, int onoff); static int ahci_ctlr_reset(device_t dev); static int ahci_ctlr_setup(device_t dev); static void ahci_begin_transaction(device_t dev, union ccb *ccb); @@ -418,6 +420,8 @@ ahci_attach(device_t dev) ctlr->caps &= ~AHCI_CAP_SNCQ; if ((ctlr->caps & AHCI_CAP_CCCS) == 0) ctlr->ccc = 0; + mtx_init(&ctlr->em_mtx, "AHCI EM lock", NULL, MTX_DEF); + ctlr->emloc = ATA_INL(ctlr->r_mem, AHCI_EM_LOC); ahci_ctlr_setup(dev); /* Setup interrupts. */ if (ahci_setup_interrupt(dev)) { @@ -521,6 +525,7 @@ ahci_detach(device_t dev) rman_fini(&ctlr->sc_iomem); if (ctlr->r_mem) bus_release_resource(dev, SYS_RES_MEMORY, ctlr->r_rid, ctlr->r_mem); + mtx_destroy(&ctlr->em_mtx); return (0); } @@ -887,6 +892,7 @@ ahci_ch_attach(device_t dev) struct cam_devq *devq; int rid, error, i, sata_rev = 0; u_int32_t version; + char buf[32]; ch->dev = dev; ch->unit = (intptr_t)device_get_ivars(dev); @@ -995,6 +1001,25 @@ ahci_ch_attach(device_t dev) ahci_ch_pm, dev); } mtx_unlock(&ch->mtx); + if ((ch->caps & AHCI_CAP_EMS) && + (ctlr->capsem & AHCI_EM_LED)) { + for (i = 0; i < AHCI_NUM_LEDS; i++) { + ch->leds[i].dev = dev; + ch->leds[i].num = i; + } + if ((ctlr->capsem & AHCI_EM_ALHD) == 0) { + snprintf(buf, sizeof(buf), "%s.act", + device_get_nameunit(dev)); + ch->leds[0].led = led_create(ahci_ch_led, + &ch->leds[0], buf); + } + snprintf(buf, sizeof(buf), "%s.locate", + device_get_nameunit(dev)); + ch->leds[1].led = led_create(ahci_ch_led, &ch->leds[1], buf); + snprintf(buf, sizeof(buf), "%s.fault", + device_get_nameunit(dev)); + ch->leds[2].led = led_create(ahci_ch_led, &ch->leds[2], buf); + } return (0); err3: @@ -1014,7 +1039,12 @@ static int ahci_ch_detach(device_t dev) { struct ahci_channel *ch = device_get_softc(dev); + int i; + for (i = 0; i < AHCI_NUM_LEDS; i++) { + if (ch->leds[i].led) + led_destroy(ch->leds[i].led); + } mtx_lock(&ch->mtx); xpt_async(AC_LOST_DEVICE, ch->path, NULL); /* Forget about reset. */ @@ -1137,6 +1167,47 @@ static driver_t ahcich_driver = { }; DRIVER_MODULE(ahcich, ahci, ahcich_driver, ahcich_devclass, 0, 0); +static void +ahci_ch_setleds(device_t dev) +{ + struct ahci_channel *ch; + struct ahci_controller *ctlr; + size_t buf; + int i, timeout; + int16_t val; + + ctlr = device_get_softc(device_get_parent(dev)); + ch = device_get_softc(dev); + + val = 0; + for (i = 0; i < AHCI_NUM_LEDS; i++) + val |= ch->leds[i].state << (i * 3); + + buf = (ctlr->emloc & 0xffff0000) >> 14; + mtx_lock(&ctlr->em_mtx); + timeout = 1000; + while (ATA_INL(ctlr->r_mem, AHCI_EM_CTL) & (AHCI_EM_TM | AHCI_EM_RST) && + --timeout > 0) + DELAY(1000); + if (timeout == 0) + device_printf(dev, "EM timeout\n"); + ATA_OUTL(ctlr->r_mem, buf, (1 << 8) | (0 << 16) | (0 << 24)); + ATA_OUTL(ctlr->r_mem, buf + 4, ch->unit | (val << 16)); + ATA_OUTL(ctlr->r_mem, AHCI_EM_CTL, AHCI_EM_TM); + mtx_unlock(&ctlr->em_mtx); +} + +static void +ahci_ch_led(void *priv, int onoff) +{ + struct ahci_led *led; + + led = (struct ahci_led *)priv; + + led->state = onoff; + ahci_ch_setleds(led->dev); +} + struct ahci_dc_cb_args { bus_addr_t maddr; int error; diff --git a/sys/dev/ahci/ahci.h b/sys/dev/ahci/ahci.h index cd5356a3f62..3ace69fff92 100644 --- a/sys/dev/ahci/ahci.h +++ b/sys/dev/ahci/ahci.h @@ -376,6 +376,15 @@ struct ahci_device { u_int caps; }; +struct ahci_led { + device_t dev; /* Device handle */ + struct cdev *led; + uint8_t num; /* Number of this led */ + uint8_t state; /* State of this led */ +}; + +#define AHCI_NUM_LEDS 3 + /* structure describing an ATA channel */ struct ahci_channel { device_t dev; /* Device handle */ @@ -386,6 +395,7 @@ struct ahci_channel { struct ata_dma dma; /* DMA data */ struct cam_sim *sim; struct cam_path *path; + struct ahci_led leds[3]; uint32_t caps; /* Controller capabilities */ uint32_t caps2; /* Controller capabilities */ uint32_t chcaps; /* Channel capabilities */ @@ -443,6 +453,7 @@ struct ahci_controller { uint32_t caps; /* Controller capabilities */ uint32_t caps2; /* Controller capabilities */ uint32_t capsem; /* Controller capabilities */ + uint32_t emloc; /* EM buffer location */ int quirks; int numirqs; int channels; @@ -453,6 +464,7 @@ struct ahci_controller { void (*function)(void *); void *argument; } interrupt[AHCI_MAX_PORTS]; + struct mtx em_mtx; /* EM access lock */ }; enum ahci_err_type { From a0a43452ae8f658aa1a6906f432845333d72b1a3 Mon Sep 17 00:00:00 2001 From: Attilio Rao Date: Tue, 17 May 2011 22:14:00 +0000 Subject: [PATCH 2/3] Merge r221285 from largeSMP project: - Remove the following sysctl: kern.sched.ipiwakeup.onecpu kern.sched.ipiwakeup.htt2 Because they are absolutely obsolete. Probabilly the whole wakeup forward mechanism should be revisited for a better fitting in modern hw, in the future. - As map2 variable is no longer used rename map3 to map2 - Fix a string by making more informative the msg and removing the arguments passing. Reviewed by: julian Tested by: several --- sys/kern/sched_4bsd.c | 38 +++++++------------------------------- 1 file changed, 7 insertions(+), 31 deletions(-) diff --git a/sys/kern/sched_4bsd.c b/sys/kern/sched_4bsd.c index 668ecd165e5..fef9e256f6b 100644 --- a/sys/kern/sched_4bsd.c +++ b/sys/kern/sched_4bsd.c @@ -235,16 +235,6 @@ SYSCTL_INT(_kern_sched_ipiwakeup, OID_AUTO, useloop, CTLFLAG_RW, &forward_wakeup_use_loop, 0, "Use a loop to find idle cpus"); -static int forward_wakeup_use_single = 0; -SYSCTL_INT(_kern_sched_ipiwakeup, OID_AUTO, onecpu, CTLFLAG_RW, - &forward_wakeup_use_single, 0, - "Only signal one idle cpu"); - -static int forward_wakeup_use_htt = 0; -SYSCTL_INT(_kern_sched_ipiwakeup, OID_AUTO, htt2, CTLFLAG_RW, - &forward_wakeup_use_htt, 0, - "account for htt"); - #endif #if 0 static int sched_followon = 0; @@ -1064,7 +1054,7 @@ static int forward_wakeup(int cpunum) { struct pcpu *pc; - cpumask_t dontuse, id, map, map2, map3, me; + cpumask_t dontuse, id, map, map2, me; mtx_assert(&sched_lock, MA_OWNED); @@ -1089,13 +1079,13 @@ forward_wakeup(int cpunum) return (0); dontuse = me | stopped_cpus | hlt_cpus_mask; - map3 = 0; + map2 = 0; if (forward_wakeup_use_loop) { SLIST_FOREACH(pc, &cpuhead, pc_allcpu) { id = pc->pc_cpumask; if ((id & dontuse) == 0 && pc->pc_curthread == pc->pc_idlethread) { - map3 |= id; + map2 |= id; } } } @@ -1106,33 +1096,19 @@ forward_wakeup(int cpunum) /* If they are both on, compare and use loop if different. */ if (forward_wakeup_use_loop) { - if (map != map3) { - printf("map (%02X) != map3 (%02X)\n", map, - map3); - map = map3; + if (map != map2) { + printf("map != map2, loop method preferred\n"); + map = map2; } } } else { - map = map3; + map = map2; } /* If we only allow a specific CPU, then mask off all the others. */ if (cpunum != NOCPU) { KASSERT((cpunum <= mp_maxcpus),("forward_wakeup: bad cpunum.")); map &= (1 << cpunum); - } else { - /* Try choose an idle die. */ - if (forward_wakeup_use_htt) { - map2 = (map & (map >> 1)) & 0x5555; - if (map2) { - map = map2; - } - } - - /* Set only one bit. */ - if (forward_wakeup_use_single) { - map = map & ((~map) + 1); - } } if (map) { forward_wakeups_delivered++; From 179efac924d0edf66e84c551b2aec4cbcbdfb9f1 Mon Sep 17 00:00:00 2001 From: Attilio Rao Date: Tue, 17 May 2011 22:15:53 +0000 Subject: [PATCH 3/3] Remove an unused typedef. Tested by: sbruno, pluknet --- sys/i386/include/xen/xenvar.h | 1 - 1 file changed, 1 deletion(-) diff --git a/sys/i386/include/xen/xenvar.h b/sys/i386/include/xen/xenvar.h index 4f8c857fb36..365930a7960 100644 --- a/sys/i386/include/xen/xenvar.h +++ b/sys/i386/include/xen/xenvar.h @@ -99,7 +99,6 @@ void xpq_init(void); (((bits)+BITS_PER_LONG-1)/BITS_PER_LONG) #define DECLARE_BITMAP(name,bits) \ unsigned long name[BITS_TO_LONGS(bits)] -typedef struct { DECLARE_BITMAP(bits, NR_CPUS); } xen_cpumask_t; int xen_create_contiguous_region(vm_page_t pages, int npages);