freebsd-dev/sys/pci/viapm.c

1019 lines
23 KiB
C
Raw Normal View History

/*-
* Copyright (c) 2001 Alcove - Nicolas Souchu
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
2003-06-11 06:34:30 +00:00
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "opt_isa.h"
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/systm.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <sys/rman.h>
#ifdef DEV_ISA
#include <isa/isavar.h>
#include <isa/isa_common.h>
#endif
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#include <dev/iicbus/iiconf.h>
#include <dev/smbus/smbconf.h>
#include "iicbb_if.h"
#include "smbus_if.h"
#define VIAPM_DEBUG(x) if (viapm_debug) (x)
#ifdef DEBUG
static int viapm_debug = 1;
#else
static int viapm_debug = 0;
#endif
#define VIA_586B_PMU_ID 0x30401106
#define VIA_596A_PMU_ID 0x30501106
#define VIA_596B_PMU_ID 0x30511106
#define VIA_686A_PMU_ID 0x30571106
#define VIA_8233_PMU_ID 0x30741106
#define VIA_8233A_PMU_ID 0x31471106
#define VIA_8235_PMU_ID 0x31771106
#define VIA_CX700_PMU_ID 0x83241106
#define VIAPM_INB(port) \
((u_char)bus_read_1(viapm->iores, port))
#define VIAPM_OUTB(port,val) \
(bus_write_1(viapm->iores, port, (u_char)(val)))
#define VIAPM_TYP_UNKNOWN 0
#define VIAPM_TYP_586B_3040E 1
#define VIAPM_TYP_586B_3040F 2
#define VIAPM_TYP_596B 3
#define VIAPM_TYP_686A 4
#define VIAPM_TYP_8233 5
#define VIAPM_LOCK(sc) mtx_lock(&(sc)->lock)
#define VIAPM_UNLOCK(sc) mtx_unlock(&(sc)->lock)
#define VIAPM_LOCK_ASSERT(sc) mtx_assert(&(sc)->lock, MA_OWNED)
struct viapm_softc {
int type;
u_int32_t base;
int iorid;
int irqrid;
struct resource *iores;
struct resource *irqres;
void *irqih;
device_t iicbb;
device_t smbus;
struct mtx lock;
};
static devclass_t viapm_devclass;
static devclass_t viapropm_devclass;
/*
* VT82C586B definitions
*/
#define VIAPM_586B_REVID 0x08
#define VIAPM_586B_3040E_BASE 0x20
#define VIAPM_586B_3040E_ACTIV 0x4 /* 16 bits */
#define VIAPM_586B_3040F_BASE 0x48
#define VIAPM_586B_3040F_ACTIV 0x41 /* 8 bits */
#define VIAPM_586B_OEM_REV_E 0x00
#define VIAPM_586B_OEM_REV_F 0x01
#define VIAPM_586B_PROD_REV_A 0x10
#define VIAPM_586B_BA_MASK 0x0000ff00
#define GPIO_DIR 0x40
#define GPIO_VAL 0x42
#define EXTSMI_VAL 0x44
#define VIAPM_SCL 0x02 /* GPIO1_VAL */
#define VIAPM_SDA 0x04 /* GPIO2_VAL */
/*
* VIAPRO common definitions
*/
#define VIAPM_PRO_BA_MASK 0x0000fff0
#define VIAPM_PRO_SMBCTRL 0xd2
#define VIAPM_PRO_REVID 0xd6
/*
* VT82C686A definitions
*/
#define VIAPM_PRO_BASE 0x90
#define SMBHST 0x0
#define SMBHSL 0x1
#define SMBHCTRL 0x2
#define SMBHCMD 0x3
#define SMBHADDR 0x4
#define SMBHDATA0 0x5
#define SMBHDATA1 0x6
#define SMBHBLOCK 0x7
#define SMBSST 0x1
#define SMBSCTRL 0x8
#define SMBSSDWCMD 0x9
#define SMBSEVENT 0xa
#define SMBSDATA 0xc
#define SMBHST_RESERVED 0xef /* reserved bits */
#define SMBHST_FAILED 0x10 /* failed bus transaction */
#define SMBHST_COLLID 0x08 /* bus collision */
#define SMBHST_ERROR 0x04 /* device error */
#define SMBHST_INTR 0x02 /* command completed */
#define SMBHST_BUSY 0x01 /* host busy */
#define SMBHCTRL_START 0x40 /* start command */
#define SMBHCTRL_PROTO 0x1c /* command protocol mask */
#define SMBHCTRL_QUICK 0x00
#define SMBHCTRL_SENDRECV 0x04
#define SMBHCTRL_BYTE 0x08
#define SMBHCTRL_WORD 0x0c
#define SMBHCTRL_BLOCK 0x14
#define SMBHCTRL_KILL 0x02 /* stop the current transaction */
#define SMBHCTRL_ENABLE 0x01 /* enable interrupts */
#define SMBSCTRL_ENABLE 0x01 /* enable slave */
/*
* VIA8233 definitions
*/
#define VIAPM_8233_BASE 0xD0
static int
viapm_586b_probe(device_t dev)
{
struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
u_int32_t l;
u_int16_t s;
u_int8_t c;
switch (pci_get_devid(dev)) {
case VIA_586B_PMU_ID:
bzero(viapm, sizeof(struct viapm_softc));
l = pci_read_config(dev, VIAPM_586B_REVID, 1);
switch (l) {
case VIAPM_586B_OEM_REV_E:
viapm->type = VIAPM_TYP_586B_3040E;
viapm->iorid = VIAPM_586B_3040E_BASE;
/* Activate IO block access */
s = pci_read_config(dev, VIAPM_586B_3040E_ACTIV, 2);
pci_write_config(dev, VIAPM_586B_3040E_ACTIV, s | 0x1, 2);
break;
case VIAPM_586B_OEM_REV_F:
case VIAPM_586B_PROD_REV_A:
default:
viapm->type = VIAPM_TYP_586B_3040F;
viapm->iorid = VIAPM_586B_3040F_BASE;
/* Activate IO block access */
c = pci_read_config(dev, VIAPM_586B_3040F_ACTIV, 1);
pci_write_config(dev, VIAPM_586B_3040F_ACTIV, c | 0x80, 1);
break;
}
viapm->base = pci_read_config(dev, viapm->iorid, 4) &
VIAPM_586B_BA_MASK;
/*
* We have to set the I/O resources by hand because it is
* described outside the viapmope of the traditional maps
*/
if (bus_set_resource(dev, SYS_RES_IOPORT, viapm->iorid,
viapm->base, 256)) {
device_printf(dev, "could not set bus resource\n");
return ENXIO;
}
device_set_desc(dev, "VIA VT82C586B Power Management Unit");
2005-02-24 21:32:56 +00:00
return (BUS_PROBE_DEFAULT);
default:
break;
}
return ENXIO;
}
static int
viapm_pro_probe(device_t dev)
{
struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
#ifdef VIAPM_BASE_ADDR
u_int32_t l;
#endif
u_int32_t base_cfgreg;
char *desc;
switch (pci_get_devid(dev)) {
case VIA_596A_PMU_ID:
desc = "VIA VT82C596A Power Management Unit";
viapm->type = VIAPM_TYP_596B;
base_cfgreg = VIAPM_PRO_BASE;
goto viapro;
case VIA_596B_PMU_ID:
desc = "VIA VT82C596B Power Management Unit";
viapm->type = VIAPM_TYP_596B;
base_cfgreg = VIAPM_PRO_BASE;
goto viapro;
case VIA_686A_PMU_ID:
desc = "VIA VT82C686A Power Management Unit";
viapm->type = VIAPM_TYP_686A;
base_cfgreg = VIAPM_PRO_BASE;
goto viapro;
case VIA_8233_PMU_ID:
case VIA_8233A_PMU_ID:
desc = "VIA VT8233 Power Management Unit";
viapm->type = VIAPM_TYP_UNKNOWN;
base_cfgreg = VIAPM_8233_BASE;
goto viapro;
case VIA_8235_PMU_ID:
desc = "VIA VT8235 Power Management Unit";
viapm->type = VIAPM_TYP_UNKNOWN;
base_cfgreg = VIAPM_8233_BASE;
goto viapro;
case VIA_CX700_PMU_ID:
desc = "VIA CX700 Power Management Unit";
viapm->type = VIAPM_TYP_UNKNOWN;
base_cfgreg = VIAPM_8233_BASE;
goto viapro;
viapro:
#ifdef VIAPM_BASE_ADDR
/* force VIAPM I/O base address */
/* enable the SMBus controller function */
l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1);
pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 1, 1);
/* write the base address */
pci_write_config(dev, base_cfgreg,
VIAPM_BASE_ADDR & VIAPM_PRO_BA_MASK, 4);
#endif
viapm->base = pci_read_config(dev, base_cfgreg, 4) & VIAPM_PRO_BA_MASK;
/*
* We have to set the I/O resources by hand because it is
* described outside the viapmope of the traditional maps
*/
viapm->iorid = base_cfgreg;
if (bus_set_resource(dev, SYS_RES_IOPORT, viapm->iorid,
viapm->base, 16)) {
device_printf(dev, "could not set bus resource 0x%x\n",
viapm->base);
return ENXIO;
}
if (bootverbose) {
device_printf(dev, "SMBus I/O base at 0x%x\n", viapm->base);
}
device_set_desc(dev, desc);
2005-02-24 21:32:56 +00:00
return (BUS_PROBE_DEFAULT);
default:
break;
}
return ENXIO;
}
static int
viapm_pro_attach(device_t dev)
{
struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
u_int32_t l;
mtx_init(&viapm->lock, device_get_nameunit(dev), "viapm", MTX_DEF);
if (!(viapm->iores = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
&viapm->iorid, RF_ACTIVE))) {
device_printf(dev, "could not allocate bus space\n");
goto error;
}
#ifdef notyet
/* force irq 9 */
l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1);
pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 0x80, 1);
viapm->irqrid = 0;
if (!(viapm->irqres = bus_alloc_resource(dev, SYS_RES_IRQ,
&viapm->irqrid, 9, 9, 1,
RF_SHAREABLE | RF_ACTIVE))) {
device_printf(dev, "could not allocate irq\n");
goto error;
}
if (bus_setup_intr(dev, viapm->irqres, INTR_TYPE_MISC | INTR_MPSAFE,
(driver_intr_t *) viasmb_intr, viapm, &viapm->irqih)) {
device_printf(dev, "could not setup irq\n");
goto error;
}
#endif
if (bootverbose) {
l = pci_read_config(dev, VIAPM_PRO_REVID, 1);
device_printf(dev, "SMBus revision code 0x%x\n", l);
}
viapm->smbus = device_add_child(dev, "smbus", -1);
/* probe and attach the smbus */
bus_generic_attach(dev);
/* disable slave function */
VIAPM_OUTB(SMBSCTRL, VIAPM_INB(SMBSCTRL) & ~SMBSCTRL_ENABLE);
/* enable the SMBus controller function */
l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1);
pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 1, 1);
#ifdef notyet
/* enable interrupts */
VIAPM_OUTB(SMBHCTRL, VIAPM_INB(SMBHCTRL) | SMBHCTRL_ENABLE);
#endif
#ifdef DEV_ISA
/* If this device is a PCI-ISA bridge, then attach an ISA bus. */
if ((pci_get_class(dev) == PCIC_BRIDGE) &&
(pci_get_subclass(dev) == PCIS_BRIDGE_ISA))
isab_attach(dev);
#endif
return 0;
error:
if (viapm->iores)
bus_release_resource(dev, SYS_RES_IOPORT, viapm->iorid, viapm->iores);
#ifdef notyet
if (viapm->irqres)
bus_release_resource(dev, SYS_RES_IRQ, viapm->irqrid, viapm->irqres);
#endif
mtx_destroy(&viapm->lock);
return ENXIO;
}
static int
viapm_586b_attach(device_t dev)
{
struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
mtx_init(&viapm->lock, device_get_nameunit(dev), "viapm", MTX_DEF);
if (!(viapm->iores = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
&viapm->iorid, RF_ACTIVE | RF_SHAREABLE))) {
device_printf(dev, "could not allocate bus resource\n");
goto error;
}
VIAPM_OUTB(GPIO_DIR, VIAPM_INB(GPIO_DIR) | VIAPM_SCL | VIAPM_SDA);
/* add generic bit-banging code */
if (!(viapm->iicbb = device_add_child(dev, "iicbb", -1)))
goto error;
bus_generic_attach(dev);
return 0;
error:
if (viapm->iores)
bus_release_resource(dev, SYS_RES_IOPORT,
viapm->iorid, viapm->iores);
mtx_destroy(&viapm->lock);
return ENXIO;
}
static int
viapm_586b_detach(device_t dev)
{
struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
bus_generic_detach(dev);
if (viapm->iicbb) {
device_delete_child(dev, viapm->iicbb);
}
if (viapm->iores)
bus_release_resource(dev, SYS_RES_IOPORT, viapm->iorid,
viapm->iores);
mtx_destroy(&viapm->lock);
return 0;
}
static int
viapm_pro_detach(device_t dev)
{
struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
bus_generic_detach(dev);
if (viapm->smbus) {
device_delete_child(dev, viapm->smbus);
}
bus_release_resource(dev, SYS_RES_IOPORT, viapm->iorid, viapm->iores);
#ifdef notyet
bus_release_resource(dev, SYS_RES_IRQ, viapm->irqrid, viapm->irqres);
#endif
mtx_destroy(&viapm->lock);
return 0;
}
static int
viabb_callback(device_t dev, int index, caddr_t *data)
{
return 0;
}
static void
viabb_setscl(device_t dev, int ctrl)
{
struct viapm_softc *viapm = device_get_softc(dev);
u_char val;
VIAPM_LOCK(viapm);
val = VIAPM_INB(GPIO_VAL);
if (ctrl)
val |= VIAPM_SCL;
else
val &= ~VIAPM_SCL;
VIAPM_OUTB(GPIO_VAL, val);
VIAPM_UNLOCK(viapm);
return;
}
static void
viabb_setsda(device_t dev, int data)
{
struct viapm_softc *viapm = device_get_softc(dev);
u_char val;
VIAPM_LOCK(viapm);
val = VIAPM_INB(GPIO_VAL);
if (data)
val |= VIAPM_SDA;
else
val &= ~VIAPM_SDA;
VIAPM_OUTB(GPIO_VAL, val);
VIAPM_UNLOCK(viapm);
return;
}
static int
viabb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
{
/* reset bus */
viabb_setsda(dev, 1);
viabb_setscl(dev, 1);
return (IIC_ENOADDR);
}
static int
viabb_getscl(device_t dev)
{
struct viapm_softc *viapm = device_get_softc(dev);
u_char val;
VIAPM_LOCK(viapm);
val = VIAPM_INB(EXTSMI_VAL);
VIAPM_UNLOCK(viapm);
return ((val & VIAPM_SCL) != 0);
}
static int
viabb_getsda(device_t dev)
{
struct viapm_softc *viapm = device_get_softc(dev);
u_char val;
VIAPM_LOCK(viapm);
val = VIAPM_INB(EXTSMI_VAL);
VIAPM_UNLOCK(viapm);
return ((val & VIAPM_SDA) != 0);
}
static int
viapm_abort(struct viapm_softc *viapm)
{
VIAPM_OUTB(SMBHCTRL, SMBHCTRL_KILL);
DELAY(10);
return (0);
}
static int
viapm_clear(struct viapm_softc *viapm)
{
VIAPM_OUTB(SMBHST, SMBHST_FAILED | SMBHST_COLLID |
SMBHST_ERROR | SMBHST_INTR);
DELAY(10);
return (0);
}
static int
viapm_busy(struct viapm_softc *viapm)
{
u_char sts;
sts = VIAPM_INB(SMBHST);
VIAPM_DEBUG(printf("viapm: idle? STS=0x%x\n", sts));
return (sts & SMBHST_BUSY);
}
/*
* Poll the SMBus controller
*/
static int
viapm_wait(struct viapm_softc *viapm)
{
int count = 10000;
u_char sts = 0;
int error;
VIAPM_LOCK_ASSERT(viapm);
/* wait for command to complete and SMBus controller is idle */
while(count--) {
DELAY(10);
sts = VIAPM_INB(SMBHST);
/* check if the controller is processing a command */
if (!(sts & SMBHST_BUSY) && (sts & SMBHST_INTR))
break;
}
VIAPM_DEBUG(printf("viapm: SMBHST=0x%x\n", sts));
error = SMB_ENOERR;
if (!count)
error |= SMB_ETIMEOUT;
if (sts & SMBHST_FAILED)
error |= SMB_EABORT;
if (sts & SMBHST_COLLID)
error |= SMB_ENOACK;
if (sts & SMBHST_ERROR)
error |= SMB_EBUSERR;
if (error != SMB_ENOERR)
viapm_abort(viapm);
viapm_clear(viapm);
return (error);
}
static int
viasmb_callback(device_t dev, int index, caddr_t *data)
{
int error = 0;
switch (index) {
case SMB_REQUEST_BUS:
case SMB_RELEASE_BUS:
/* ok, bus allocation accepted */
break;
default:
error = EINVAL;
}
return (error);
}
static int
viasmb_quick(device_t dev, u_char slave, int how)
{
struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
int error;
VIAPM_LOCK(viapm);
viapm_clear(viapm);
if (viapm_busy(viapm)) {
VIAPM_UNLOCK(viapm);
Minor overhaul of SMBus support: - Change smbus_callback() to pass a void * rather than caddr_t. - Change smbus_bread() to pass a pointer to the count and have it be an in/out parameter. The input is the size of the buffer (same as before), but on return it will contain the actual amount of data read back from the bus. Note that this value may be larger than the input value. It is up to the caller to treat this as an error if desired. - Change the SMB_BREAD ioctl to write out the updated struct smbcmd which will contain the actual number of bytes read in the 'count' field. To preserve the previous ABI, the old ioctl value is mapped to SMB_OLD_BREAD which doesn't copy the updated smbcmd back out to userland. I doubt anyone actually used the old BREAD anyway as it was rediculous to do a bulk-read but not tell the using program how much data was actually read. - Make the smbus driver and devclass public in the smbus module and push all the DRIVER_MODULE()'s for attaching the smbus driver to various foosmb drivers out into the foosmb modules. This makes all the foosmb logic centralized and allows new foosmb modules to be self-contained w/o having to hack smbus.c everytime a new smbus driver is added. - Add a new SMB_EINVAL error bit and use it in place of EINVAL to return an error for bad arguments (such as invalid counts for bread and bwrite). - Map SMB bus error bits to EIO in smbus_error(). - Make the smbus driver call bus_generic_probe() and require child drivers such as smb(4) to create device_t's via identify routines. Previously, smbus just created one anonymous device during attach, and if you had multiple drivers that could attach it was just random chance as to which driver got to probe for the sole device_t first. - Add a mutex to the smbus(4) softc and use it in place of dummy splhigh() to protect the 'owner' field and perform necessary synchronization for smbus_request_bus() and smbus_release_bus(). - Change the bread() and bwrite() methods of alpm(4), amdpm(4), and viapm(4) to only perform a single transaction and not try to use a loop of multiple transactions for a large request. The framing and commands to use for a large transaction depend on the upper-layer protocol (such as SSIF for IPMI over SMBus) from what I can tell, and the smb(4) driver never allowed bulk read/writes of more than 32-bytes anyway. The other smb drivers only performed single transactions. - Fix buffer overflows in the bread() methods of ichsmb(4), alpm(4), amdpm(4), amdsmb(4), intpm(4), and nfsmb(4). - Use SMB_xxx errors in viapm(4). - Destroy ichsmb(4)'s mutex after bus_generic_detach() to avoid problems from child devices making smb upcalls that would use the mutex during their detach methods. MFC after: 1 week Reviewed by: jmg (mostly)
2006-09-11 20:52:41 +00:00
return (SMB_EBUSY);
}
switch (how) {
case SMB_QWRITE:
VIAPM_DEBUG(printf("viapm: QWRITE to 0x%x", slave));
VIAPM_OUTB(SMBHADDR, slave & ~LSB);
break;
case SMB_QREAD:
VIAPM_DEBUG(printf("viapm: QREAD to 0x%x", slave));
VIAPM_OUTB(SMBHADDR, slave | LSB);
break;
default:
panic("%s: unknown QUICK command (%x)!", __func__, how);
}
VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_QUICK);
error = viapm_wait(viapm);
VIAPM_UNLOCK(viapm);
return (error);
}
static int
viasmb_sendb(device_t dev, u_char slave, char byte)
{
struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
int error;
VIAPM_LOCK(viapm);
viapm_clear(viapm);
if (viapm_busy(viapm)) {
VIAPM_UNLOCK(viapm);
Minor overhaul of SMBus support: - Change smbus_callback() to pass a void * rather than caddr_t. - Change smbus_bread() to pass a pointer to the count and have it be an in/out parameter. The input is the size of the buffer (same as before), but on return it will contain the actual amount of data read back from the bus. Note that this value may be larger than the input value. It is up to the caller to treat this as an error if desired. - Change the SMB_BREAD ioctl to write out the updated struct smbcmd which will contain the actual number of bytes read in the 'count' field. To preserve the previous ABI, the old ioctl value is mapped to SMB_OLD_BREAD which doesn't copy the updated smbcmd back out to userland. I doubt anyone actually used the old BREAD anyway as it was rediculous to do a bulk-read but not tell the using program how much data was actually read. - Make the smbus driver and devclass public in the smbus module and push all the DRIVER_MODULE()'s for attaching the smbus driver to various foosmb drivers out into the foosmb modules. This makes all the foosmb logic centralized and allows new foosmb modules to be self-contained w/o having to hack smbus.c everytime a new smbus driver is added. - Add a new SMB_EINVAL error bit and use it in place of EINVAL to return an error for bad arguments (such as invalid counts for bread and bwrite). - Map SMB bus error bits to EIO in smbus_error(). - Make the smbus driver call bus_generic_probe() and require child drivers such as smb(4) to create device_t's via identify routines. Previously, smbus just created one anonymous device during attach, and if you had multiple drivers that could attach it was just random chance as to which driver got to probe for the sole device_t first. - Add a mutex to the smbus(4) softc and use it in place of dummy splhigh() to protect the 'owner' field and perform necessary synchronization for smbus_request_bus() and smbus_release_bus(). - Change the bread() and bwrite() methods of alpm(4), amdpm(4), and viapm(4) to only perform a single transaction and not try to use a loop of multiple transactions for a large request. The framing and commands to use for a large transaction depend on the upper-layer protocol (such as SSIF for IPMI over SMBus) from what I can tell, and the smb(4) driver never allowed bulk read/writes of more than 32-bytes anyway. The other smb drivers only performed single transactions. - Fix buffer overflows in the bread() methods of ichsmb(4), alpm(4), amdpm(4), amdsmb(4), intpm(4), and nfsmb(4). - Use SMB_xxx errors in viapm(4). - Destroy ichsmb(4)'s mutex after bus_generic_detach() to avoid problems from child devices making smb upcalls that would use the mutex during their detach methods. MFC after: 1 week Reviewed by: jmg (mostly)
2006-09-11 20:52:41 +00:00
return (SMB_EBUSY);
}
VIAPM_OUTB(SMBHADDR, slave & ~ LSB);
VIAPM_OUTB(SMBHCMD, byte);
VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_SENDRECV);
error = viapm_wait(viapm);
VIAPM_DEBUG(printf("viapm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error));
VIAPM_UNLOCK(viapm);
return (error);
}
static int
viasmb_recvb(device_t dev, u_char slave, char *byte)
{
struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
int error;
VIAPM_LOCK(viapm);
viapm_clear(viapm);
if (viapm_busy(viapm)) {
VIAPM_UNLOCK(viapm);
Minor overhaul of SMBus support: - Change smbus_callback() to pass a void * rather than caddr_t. - Change smbus_bread() to pass a pointer to the count and have it be an in/out parameter. The input is the size of the buffer (same as before), but on return it will contain the actual amount of data read back from the bus. Note that this value may be larger than the input value. It is up to the caller to treat this as an error if desired. - Change the SMB_BREAD ioctl to write out the updated struct smbcmd which will contain the actual number of bytes read in the 'count' field. To preserve the previous ABI, the old ioctl value is mapped to SMB_OLD_BREAD which doesn't copy the updated smbcmd back out to userland. I doubt anyone actually used the old BREAD anyway as it was rediculous to do a bulk-read but not tell the using program how much data was actually read. - Make the smbus driver and devclass public in the smbus module and push all the DRIVER_MODULE()'s for attaching the smbus driver to various foosmb drivers out into the foosmb modules. This makes all the foosmb logic centralized and allows new foosmb modules to be self-contained w/o having to hack smbus.c everytime a new smbus driver is added. - Add a new SMB_EINVAL error bit and use it in place of EINVAL to return an error for bad arguments (such as invalid counts for bread and bwrite). - Map SMB bus error bits to EIO in smbus_error(). - Make the smbus driver call bus_generic_probe() and require child drivers such as smb(4) to create device_t's via identify routines. Previously, smbus just created one anonymous device during attach, and if you had multiple drivers that could attach it was just random chance as to which driver got to probe for the sole device_t first. - Add a mutex to the smbus(4) softc and use it in place of dummy splhigh() to protect the 'owner' field and perform necessary synchronization for smbus_request_bus() and smbus_release_bus(). - Change the bread() and bwrite() methods of alpm(4), amdpm(4), and viapm(4) to only perform a single transaction and not try to use a loop of multiple transactions for a large request. The framing and commands to use for a large transaction depend on the upper-layer protocol (such as SSIF for IPMI over SMBus) from what I can tell, and the smb(4) driver never allowed bulk read/writes of more than 32-bytes anyway. The other smb drivers only performed single transactions. - Fix buffer overflows in the bread() methods of ichsmb(4), alpm(4), amdpm(4), amdsmb(4), intpm(4), and nfsmb(4). - Use SMB_xxx errors in viapm(4). - Destroy ichsmb(4)'s mutex after bus_generic_detach() to avoid problems from child devices making smb upcalls that would use the mutex during their detach methods. MFC after: 1 week Reviewed by: jmg (mostly)
2006-09-11 20:52:41 +00:00
return (SMB_EBUSY);
}
VIAPM_OUTB(SMBHADDR, slave | LSB);
VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_SENDRECV);
if ((error = viapm_wait(viapm)) == SMB_ENOERR)
*byte = VIAPM_INB(SMBHDATA0);
VIAPM_DEBUG(printf("viapm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error));
VIAPM_UNLOCK(viapm);
return (error);
}
static int
viasmb_writeb(device_t dev, u_char slave, char cmd, char byte)
{
struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
int error;
VIAPM_LOCK(viapm);
viapm_clear(viapm);
if (viapm_busy(viapm)) {
VIAPM_UNLOCK(viapm);
Minor overhaul of SMBus support: - Change smbus_callback() to pass a void * rather than caddr_t. - Change smbus_bread() to pass a pointer to the count and have it be an in/out parameter. The input is the size of the buffer (same as before), but on return it will contain the actual amount of data read back from the bus. Note that this value may be larger than the input value. It is up to the caller to treat this as an error if desired. - Change the SMB_BREAD ioctl to write out the updated struct smbcmd which will contain the actual number of bytes read in the 'count' field. To preserve the previous ABI, the old ioctl value is mapped to SMB_OLD_BREAD which doesn't copy the updated smbcmd back out to userland. I doubt anyone actually used the old BREAD anyway as it was rediculous to do a bulk-read but not tell the using program how much data was actually read. - Make the smbus driver and devclass public in the smbus module and push all the DRIVER_MODULE()'s for attaching the smbus driver to various foosmb drivers out into the foosmb modules. This makes all the foosmb logic centralized and allows new foosmb modules to be self-contained w/o having to hack smbus.c everytime a new smbus driver is added. - Add a new SMB_EINVAL error bit and use it in place of EINVAL to return an error for bad arguments (such as invalid counts for bread and bwrite). - Map SMB bus error bits to EIO in smbus_error(). - Make the smbus driver call bus_generic_probe() and require child drivers such as smb(4) to create device_t's via identify routines. Previously, smbus just created one anonymous device during attach, and if you had multiple drivers that could attach it was just random chance as to which driver got to probe for the sole device_t first. - Add a mutex to the smbus(4) softc and use it in place of dummy splhigh() to protect the 'owner' field and perform necessary synchronization for smbus_request_bus() and smbus_release_bus(). - Change the bread() and bwrite() methods of alpm(4), amdpm(4), and viapm(4) to only perform a single transaction and not try to use a loop of multiple transactions for a large request. The framing and commands to use for a large transaction depend on the upper-layer protocol (such as SSIF for IPMI over SMBus) from what I can tell, and the smb(4) driver never allowed bulk read/writes of more than 32-bytes anyway. The other smb drivers only performed single transactions. - Fix buffer overflows in the bread() methods of ichsmb(4), alpm(4), amdpm(4), amdsmb(4), intpm(4), and nfsmb(4). - Use SMB_xxx errors in viapm(4). - Destroy ichsmb(4)'s mutex after bus_generic_detach() to avoid problems from child devices making smb upcalls that would use the mutex during their detach methods. MFC after: 1 week Reviewed by: jmg (mostly)
2006-09-11 20:52:41 +00:00
return (SMB_EBUSY);
}
VIAPM_OUTB(SMBHADDR, slave & ~ LSB);
VIAPM_OUTB(SMBHCMD, cmd);
VIAPM_OUTB(SMBHDATA0, byte);
VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BYTE);
error = viapm_wait(viapm);
VIAPM_DEBUG(printf("viapm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error));
VIAPM_UNLOCK(viapm);
return (error);
}
static int
viasmb_readb(device_t dev, u_char slave, char cmd, char *byte)
{
struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
int error;
VIAPM_LOCK(viapm);
viapm_clear(viapm);
if (viapm_busy(viapm)) {
VIAPM_UNLOCK(viapm);
Minor overhaul of SMBus support: - Change smbus_callback() to pass a void * rather than caddr_t. - Change smbus_bread() to pass a pointer to the count and have it be an in/out parameter. The input is the size of the buffer (same as before), but on return it will contain the actual amount of data read back from the bus. Note that this value may be larger than the input value. It is up to the caller to treat this as an error if desired. - Change the SMB_BREAD ioctl to write out the updated struct smbcmd which will contain the actual number of bytes read in the 'count' field. To preserve the previous ABI, the old ioctl value is mapped to SMB_OLD_BREAD which doesn't copy the updated smbcmd back out to userland. I doubt anyone actually used the old BREAD anyway as it was rediculous to do a bulk-read but not tell the using program how much data was actually read. - Make the smbus driver and devclass public in the smbus module and push all the DRIVER_MODULE()'s for attaching the smbus driver to various foosmb drivers out into the foosmb modules. This makes all the foosmb logic centralized and allows new foosmb modules to be self-contained w/o having to hack smbus.c everytime a new smbus driver is added. - Add a new SMB_EINVAL error bit and use it in place of EINVAL to return an error for bad arguments (such as invalid counts for bread and bwrite). - Map SMB bus error bits to EIO in smbus_error(). - Make the smbus driver call bus_generic_probe() and require child drivers such as smb(4) to create device_t's via identify routines. Previously, smbus just created one anonymous device during attach, and if you had multiple drivers that could attach it was just random chance as to which driver got to probe for the sole device_t first. - Add a mutex to the smbus(4) softc and use it in place of dummy splhigh() to protect the 'owner' field and perform necessary synchronization for smbus_request_bus() and smbus_release_bus(). - Change the bread() and bwrite() methods of alpm(4), amdpm(4), and viapm(4) to only perform a single transaction and not try to use a loop of multiple transactions for a large request. The framing and commands to use for a large transaction depend on the upper-layer protocol (such as SSIF for IPMI over SMBus) from what I can tell, and the smb(4) driver never allowed bulk read/writes of more than 32-bytes anyway. The other smb drivers only performed single transactions. - Fix buffer overflows in the bread() methods of ichsmb(4), alpm(4), amdpm(4), amdsmb(4), intpm(4), and nfsmb(4). - Use SMB_xxx errors in viapm(4). - Destroy ichsmb(4)'s mutex after bus_generic_detach() to avoid problems from child devices making smb upcalls that would use the mutex during their detach methods. MFC after: 1 week Reviewed by: jmg (mostly)
2006-09-11 20:52:41 +00:00
return (SMB_EBUSY);
}
VIAPM_OUTB(SMBHADDR, slave | LSB);
VIAPM_OUTB(SMBHCMD, cmd);
VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BYTE);
if ((error = viapm_wait(viapm)) == SMB_ENOERR)
*byte = VIAPM_INB(SMBHDATA0);
VIAPM_DEBUG(printf("viapm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error));
VIAPM_UNLOCK(viapm);
return (error);
}
static int
viasmb_writew(device_t dev, u_char slave, char cmd, short word)
{
struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
int error;
VIAPM_LOCK(viapm);
viapm_clear(viapm);
if (viapm_busy(viapm)) {
VIAPM_UNLOCK(viapm);
Minor overhaul of SMBus support: - Change smbus_callback() to pass a void * rather than caddr_t. - Change smbus_bread() to pass a pointer to the count and have it be an in/out parameter. The input is the size of the buffer (same as before), but on return it will contain the actual amount of data read back from the bus. Note that this value may be larger than the input value. It is up to the caller to treat this as an error if desired. - Change the SMB_BREAD ioctl to write out the updated struct smbcmd which will contain the actual number of bytes read in the 'count' field. To preserve the previous ABI, the old ioctl value is mapped to SMB_OLD_BREAD which doesn't copy the updated smbcmd back out to userland. I doubt anyone actually used the old BREAD anyway as it was rediculous to do a bulk-read but not tell the using program how much data was actually read. - Make the smbus driver and devclass public in the smbus module and push all the DRIVER_MODULE()'s for attaching the smbus driver to various foosmb drivers out into the foosmb modules. This makes all the foosmb logic centralized and allows new foosmb modules to be self-contained w/o having to hack smbus.c everytime a new smbus driver is added. - Add a new SMB_EINVAL error bit and use it in place of EINVAL to return an error for bad arguments (such as invalid counts for bread and bwrite). - Map SMB bus error bits to EIO in smbus_error(). - Make the smbus driver call bus_generic_probe() and require child drivers such as smb(4) to create device_t's via identify routines. Previously, smbus just created one anonymous device during attach, and if you had multiple drivers that could attach it was just random chance as to which driver got to probe for the sole device_t first. - Add a mutex to the smbus(4) softc and use it in place of dummy splhigh() to protect the 'owner' field and perform necessary synchronization for smbus_request_bus() and smbus_release_bus(). - Change the bread() and bwrite() methods of alpm(4), amdpm(4), and viapm(4) to only perform a single transaction and not try to use a loop of multiple transactions for a large request. The framing and commands to use for a large transaction depend on the upper-layer protocol (such as SSIF for IPMI over SMBus) from what I can tell, and the smb(4) driver never allowed bulk read/writes of more than 32-bytes anyway. The other smb drivers only performed single transactions. - Fix buffer overflows in the bread() methods of ichsmb(4), alpm(4), amdpm(4), amdsmb(4), intpm(4), and nfsmb(4). - Use SMB_xxx errors in viapm(4). - Destroy ichsmb(4)'s mutex after bus_generic_detach() to avoid problems from child devices making smb upcalls that would use the mutex during their detach methods. MFC after: 1 week Reviewed by: jmg (mostly)
2006-09-11 20:52:41 +00:00
return (SMB_EBUSY);
}
VIAPM_OUTB(SMBHADDR, slave & ~ LSB);
VIAPM_OUTB(SMBHCMD, cmd);
VIAPM_OUTB(SMBHDATA0, word & 0x00ff);
VIAPM_OUTB(SMBHDATA1, (word & 0xff00) >> 8);
VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_WORD);
error = viapm_wait(viapm);
VIAPM_DEBUG(printf("viapm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error));
VIAPM_UNLOCK(viapm);
return (error);
}
static int
viasmb_readw(device_t dev, u_char slave, char cmd, short *word)
{
struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
int error;
u_char high, low;
VIAPM_LOCK(viapm);
viapm_clear(viapm);
if (viapm_busy(viapm)) {
VIAPM_UNLOCK(viapm);
Minor overhaul of SMBus support: - Change smbus_callback() to pass a void * rather than caddr_t. - Change smbus_bread() to pass a pointer to the count and have it be an in/out parameter. The input is the size of the buffer (same as before), but on return it will contain the actual amount of data read back from the bus. Note that this value may be larger than the input value. It is up to the caller to treat this as an error if desired. - Change the SMB_BREAD ioctl to write out the updated struct smbcmd which will contain the actual number of bytes read in the 'count' field. To preserve the previous ABI, the old ioctl value is mapped to SMB_OLD_BREAD which doesn't copy the updated smbcmd back out to userland. I doubt anyone actually used the old BREAD anyway as it was rediculous to do a bulk-read but not tell the using program how much data was actually read. - Make the smbus driver and devclass public in the smbus module and push all the DRIVER_MODULE()'s for attaching the smbus driver to various foosmb drivers out into the foosmb modules. This makes all the foosmb logic centralized and allows new foosmb modules to be self-contained w/o having to hack smbus.c everytime a new smbus driver is added. - Add a new SMB_EINVAL error bit and use it in place of EINVAL to return an error for bad arguments (such as invalid counts for bread and bwrite). - Map SMB bus error bits to EIO in smbus_error(). - Make the smbus driver call bus_generic_probe() and require child drivers such as smb(4) to create device_t's via identify routines. Previously, smbus just created one anonymous device during attach, and if you had multiple drivers that could attach it was just random chance as to which driver got to probe for the sole device_t first. - Add a mutex to the smbus(4) softc and use it in place of dummy splhigh() to protect the 'owner' field and perform necessary synchronization for smbus_request_bus() and smbus_release_bus(). - Change the bread() and bwrite() methods of alpm(4), amdpm(4), and viapm(4) to only perform a single transaction and not try to use a loop of multiple transactions for a large request. The framing and commands to use for a large transaction depend on the upper-layer protocol (such as SSIF for IPMI over SMBus) from what I can tell, and the smb(4) driver never allowed bulk read/writes of more than 32-bytes anyway. The other smb drivers only performed single transactions. - Fix buffer overflows in the bread() methods of ichsmb(4), alpm(4), amdpm(4), amdsmb(4), intpm(4), and nfsmb(4). - Use SMB_xxx errors in viapm(4). - Destroy ichsmb(4)'s mutex after bus_generic_detach() to avoid problems from child devices making smb upcalls that would use the mutex during their detach methods. MFC after: 1 week Reviewed by: jmg (mostly)
2006-09-11 20:52:41 +00:00
return (SMB_EBUSY);
}
VIAPM_OUTB(SMBHADDR, slave | LSB);
VIAPM_OUTB(SMBHCMD, cmd);
VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_WORD);
if ((error = viapm_wait(viapm)) == SMB_ENOERR) {
low = VIAPM_INB(SMBHDATA0);
high = VIAPM_INB(SMBHDATA1);
*word = ((high & 0xff) << 8) | (low & 0xff);
}
VIAPM_DEBUG(printf("viapm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error));
VIAPM_UNLOCK(viapm);
return (error);
}
static int
viasmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
{
struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
Minor overhaul of SMBus support: - Change smbus_callback() to pass a void * rather than caddr_t. - Change smbus_bread() to pass a pointer to the count and have it be an in/out parameter. The input is the size of the buffer (same as before), but on return it will contain the actual amount of data read back from the bus. Note that this value may be larger than the input value. It is up to the caller to treat this as an error if desired. - Change the SMB_BREAD ioctl to write out the updated struct smbcmd which will contain the actual number of bytes read in the 'count' field. To preserve the previous ABI, the old ioctl value is mapped to SMB_OLD_BREAD which doesn't copy the updated smbcmd back out to userland. I doubt anyone actually used the old BREAD anyway as it was rediculous to do a bulk-read but not tell the using program how much data was actually read. - Make the smbus driver and devclass public in the smbus module and push all the DRIVER_MODULE()'s for attaching the smbus driver to various foosmb drivers out into the foosmb modules. This makes all the foosmb logic centralized and allows new foosmb modules to be self-contained w/o having to hack smbus.c everytime a new smbus driver is added. - Add a new SMB_EINVAL error bit and use it in place of EINVAL to return an error for bad arguments (such as invalid counts for bread and bwrite). - Map SMB bus error bits to EIO in smbus_error(). - Make the smbus driver call bus_generic_probe() and require child drivers such as smb(4) to create device_t's via identify routines. Previously, smbus just created one anonymous device during attach, and if you had multiple drivers that could attach it was just random chance as to which driver got to probe for the sole device_t first. - Add a mutex to the smbus(4) softc and use it in place of dummy splhigh() to protect the 'owner' field and perform necessary synchronization for smbus_request_bus() and smbus_release_bus(). - Change the bread() and bwrite() methods of alpm(4), amdpm(4), and viapm(4) to only perform a single transaction and not try to use a loop of multiple transactions for a large request. The framing and commands to use for a large transaction depend on the upper-layer protocol (such as SSIF for IPMI over SMBus) from what I can tell, and the smb(4) driver never allowed bulk read/writes of more than 32-bytes anyway. The other smb drivers only performed single transactions. - Fix buffer overflows in the bread() methods of ichsmb(4), alpm(4), amdpm(4), amdsmb(4), intpm(4), and nfsmb(4). - Use SMB_xxx errors in viapm(4). - Destroy ichsmb(4)'s mutex after bus_generic_detach() to avoid problems from child devices making smb upcalls that would use the mutex during their detach methods. MFC after: 1 week Reviewed by: jmg (mostly)
2006-09-11 20:52:41 +00:00
u_char i;
int error;
if (count < 1 || count > 32)
return (SMB_EINVAL);
VIAPM_LOCK(viapm);
viapm_clear(viapm);
if (viapm_busy(viapm)) {
VIAPM_UNLOCK(viapm);
Minor overhaul of SMBus support: - Change smbus_callback() to pass a void * rather than caddr_t. - Change smbus_bread() to pass a pointer to the count and have it be an in/out parameter. The input is the size of the buffer (same as before), but on return it will contain the actual amount of data read back from the bus. Note that this value may be larger than the input value. It is up to the caller to treat this as an error if desired. - Change the SMB_BREAD ioctl to write out the updated struct smbcmd which will contain the actual number of bytes read in the 'count' field. To preserve the previous ABI, the old ioctl value is mapped to SMB_OLD_BREAD which doesn't copy the updated smbcmd back out to userland. I doubt anyone actually used the old BREAD anyway as it was rediculous to do a bulk-read but not tell the using program how much data was actually read. - Make the smbus driver and devclass public in the smbus module and push all the DRIVER_MODULE()'s for attaching the smbus driver to various foosmb drivers out into the foosmb modules. This makes all the foosmb logic centralized and allows new foosmb modules to be self-contained w/o having to hack smbus.c everytime a new smbus driver is added. - Add a new SMB_EINVAL error bit and use it in place of EINVAL to return an error for bad arguments (such as invalid counts for bread and bwrite). - Map SMB bus error bits to EIO in smbus_error(). - Make the smbus driver call bus_generic_probe() and require child drivers such as smb(4) to create device_t's via identify routines. Previously, smbus just created one anonymous device during attach, and if you had multiple drivers that could attach it was just random chance as to which driver got to probe for the sole device_t first. - Add a mutex to the smbus(4) softc and use it in place of dummy splhigh() to protect the 'owner' field and perform necessary synchronization for smbus_request_bus() and smbus_release_bus(). - Change the bread() and bwrite() methods of alpm(4), amdpm(4), and viapm(4) to only perform a single transaction and not try to use a loop of multiple transactions for a large request. The framing and commands to use for a large transaction depend on the upper-layer protocol (such as SSIF for IPMI over SMBus) from what I can tell, and the smb(4) driver never allowed bulk read/writes of more than 32-bytes anyway. The other smb drivers only performed single transactions. - Fix buffer overflows in the bread() methods of ichsmb(4), alpm(4), amdpm(4), amdsmb(4), intpm(4), and nfsmb(4). - Use SMB_xxx errors in viapm(4). - Destroy ichsmb(4)'s mutex after bus_generic_detach() to avoid problems from child devices making smb upcalls that would use the mutex during their detach methods. MFC after: 1 week Reviewed by: jmg (mostly)
2006-09-11 20:52:41 +00:00
return (SMB_EBUSY);
}
Minor overhaul of SMBus support: - Change smbus_callback() to pass a void * rather than caddr_t. - Change smbus_bread() to pass a pointer to the count and have it be an in/out parameter. The input is the size of the buffer (same as before), but on return it will contain the actual amount of data read back from the bus. Note that this value may be larger than the input value. It is up to the caller to treat this as an error if desired. - Change the SMB_BREAD ioctl to write out the updated struct smbcmd which will contain the actual number of bytes read in the 'count' field. To preserve the previous ABI, the old ioctl value is mapped to SMB_OLD_BREAD which doesn't copy the updated smbcmd back out to userland. I doubt anyone actually used the old BREAD anyway as it was rediculous to do a bulk-read but not tell the using program how much data was actually read. - Make the smbus driver and devclass public in the smbus module and push all the DRIVER_MODULE()'s for attaching the smbus driver to various foosmb drivers out into the foosmb modules. This makes all the foosmb logic centralized and allows new foosmb modules to be self-contained w/o having to hack smbus.c everytime a new smbus driver is added. - Add a new SMB_EINVAL error bit and use it in place of EINVAL to return an error for bad arguments (such as invalid counts for bread and bwrite). - Map SMB bus error bits to EIO in smbus_error(). - Make the smbus driver call bus_generic_probe() and require child drivers such as smb(4) to create device_t's via identify routines. Previously, smbus just created one anonymous device during attach, and if you had multiple drivers that could attach it was just random chance as to which driver got to probe for the sole device_t first. - Add a mutex to the smbus(4) softc and use it in place of dummy splhigh() to protect the 'owner' field and perform necessary synchronization for smbus_request_bus() and smbus_release_bus(). - Change the bread() and bwrite() methods of alpm(4), amdpm(4), and viapm(4) to only perform a single transaction and not try to use a loop of multiple transactions for a large request. The framing and commands to use for a large transaction depend on the upper-layer protocol (such as SSIF for IPMI over SMBus) from what I can tell, and the smb(4) driver never allowed bulk read/writes of more than 32-bytes anyway. The other smb drivers only performed single transactions. - Fix buffer overflows in the bread() methods of ichsmb(4), alpm(4), amdpm(4), amdsmb(4), intpm(4), and nfsmb(4). - Use SMB_xxx errors in viapm(4). - Destroy ichsmb(4)'s mutex after bus_generic_detach() to avoid problems from child devices making smb upcalls that would use the mutex during their detach methods. MFC after: 1 week Reviewed by: jmg (mostly)
2006-09-11 20:52:41 +00:00
VIAPM_OUTB(SMBHADDR, slave & ~LSB);
VIAPM_OUTB(SMBHCMD, cmd);
VIAPM_OUTB(SMBHDATA0, count);
i = VIAPM_INB(SMBHCTRL);
Minor overhaul of SMBus support: - Change smbus_callback() to pass a void * rather than caddr_t. - Change smbus_bread() to pass a pointer to the count and have it be an in/out parameter. The input is the size of the buffer (same as before), but on return it will contain the actual amount of data read back from the bus. Note that this value may be larger than the input value. It is up to the caller to treat this as an error if desired. - Change the SMB_BREAD ioctl to write out the updated struct smbcmd which will contain the actual number of bytes read in the 'count' field. To preserve the previous ABI, the old ioctl value is mapped to SMB_OLD_BREAD which doesn't copy the updated smbcmd back out to userland. I doubt anyone actually used the old BREAD anyway as it was rediculous to do a bulk-read but not tell the using program how much data was actually read. - Make the smbus driver and devclass public in the smbus module and push all the DRIVER_MODULE()'s for attaching the smbus driver to various foosmb drivers out into the foosmb modules. This makes all the foosmb logic centralized and allows new foosmb modules to be self-contained w/o having to hack smbus.c everytime a new smbus driver is added. - Add a new SMB_EINVAL error bit and use it in place of EINVAL to return an error for bad arguments (such as invalid counts for bread and bwrite). - Map SMB bus error bits to EIO in smbus_error(). - Make the smbus driver call bus_generic_probe() and require child drivers such as smb(4) to create device_t's via identify routines. Previously, smbus just created one anonymous device during attach, and if you had multiple drivers that could attach it was just random chance as to which driver got to probe for the sole device_t first. - Add a mutex to the smbus(4) softc and use it in place of dummy splhigh() to protect the 'owner' field and perform necessary synchronization for smbus_request_bus() and smbus_release_bus(). - Change the bread() and bwrite() methods of alpm(4), amdpm(4), and viapm(4) to only perform a single transaction and not try to use a loop of multiple transactions for a large request. The framing and commands to use for a large transaction depend on the upper-layer protocol (such as SSIF for IPMI over SMBus) from what I can tell, and the smb(4) driver never allowed bulk read/writes of more than 32-bytes anyway. The other smb drivers only performed single transactions. - Fix buffer overflows in the bread() methods of ichsmb(4), alpm(4), amdpm(4), amdsmb(4), intpm(4), and nfsmb(4). - Use SMB_xxx errors in viapm(4). - Destroy ichsmb(4)'s mutex after bus_generic_detach() to avoid problems from child devices making smb upcalls that would use the mutex during their detach methods. MFC after: 1 week Reviewed by: jmg (mostly)
2006-09-11 20:52:41 +00:00
/* fill the 32-byte internal buffer */
for (i = 0; i < count; i++) {
VIAPM_OUTB(SMBHBLOCK, buf[i]);
DELAY(2);
}
Minor overhaul of SMBus support: - Change smbus_callback() to pass a void * rather than caddr_t. - Change smbus_bread() to pass a pointer to the count and have it be an in/out parameter. The input is the size of the buffer (same as before), but on return it will contain the actual amount of data read back from the bus. Note that this value may be larger than the input value. It is up to the caller to treat this as an error if desired. - Change the SMB_BREAD ioctl to write out the updated struct smbcmd which will contain the actual number of bytes read in the 'count' field. To preserve the previous ABI, the old ioctl value is mapped to SMB_OLD_BREAD which doesn't copy the updated smbcmd back out to userland. I doubt anyone actually used the old BREAD anyway as it was rediculous to do a bulk-read but not tell the using program how much data was actually read. - Make the smbus driver and devclass public in the smbus module and push all the DRIVER_MODULE()'s for attaching the smbus driver to various foosmb drivers out into the foosmb modules. This makes all the foosmb logic centralized and allows new foosmb modules to be self-contained w/o having to hack smbus.c everytime a new smbus driver is added. - Add a new SMB_EINVAL error bit and use it in place of EINVAL to return an error for bad arguments (such as invalid counts for bread and bwrite). - Map SMB bus error bits to EIO in smbus_error(). - Make the smbus driver call bus_generic_probe() and require child drivers such as smb(4) to create device_t's via identify routines. Previously, smbus just created one anonymous device during attach, and if you had multiple drivers that could attach it was just random chance as to which driver got to probe for the sole device_t first. - Add a mutex to the smbus(4) softc and use it in place of dummy splhigh() to protect the 'owner' field and perform necessary synchronization for smbus_request_bus() and smbus_release_bus(). - Change the bread() and bwrite() methods of alpm(4), amdpm(4), and viapm(4) to only perform a single transaction and not try to use a loop of multiple transactions for a large request. The framing and commands to use for a large transaction depend on the upper-layer protocol (such as SSIF for IPMI over SMBus) from what I can tell, and the smb(4) driver never allowed bulk read/writes of more than 32-bytes anyway. The other smb drivers only performed single transactions. - Fix buffer overflows in the bread() methods of ichsmb(4), alpm(4), amdpm(4), amdsmb(4), intpm(4), and nfsmb(4). - Use SMB_xxx errors in viapm(4). - Destroy ichsmb(4)'s mutex after bus_generic_detach() to avoid problems from child devices making smb upcalls that would use the mutex during their detach methods. MFC after: 1 week Reviewed by: jmg (mostly)
2006-09-11 20:52:41 +00:00
VIAPM_OUTB(SMBHCMD, cmd);
VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BLOCK);
error = viapm_wait(viapm);
VIAPM_DEBUG(printf("viapm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
VIAPM_UNLOCK(viapm);
return (error);
}
static int
Minor overhaul of SMBus support: - Change smbus_callback() to pass a void * rather than caddr_t. - Change smbus_bread() to pass a pointer to the count and have it be an in/out parameter. The input is the size of the buffer (same as before), but on return it will contain the actual amount of data read back from the bus. Note that this value may be larger than the input value. It is up to the caller to treat this as an error if desired. - Change the SMB_BREAD ioctl to write out the updated struct smbcmd which will contain the actual number of bytes read in the 'count' field. To preserve the previous ABI, the old ioctl value is mapped to SMB_OLD_BREAD which doesn't copy the updated smbcmd back out to userland. I doubt anyone actually used the old BREAD anyway as it was rediculous to do a bulk-read but not tell the using program how much data was actually read. - Make the smbus driver and devclass public in the smbus module and push all the DRIVER_MODULE()'s for attaching the smbus driver to various foosmb drivers out into the foosmb modules. This makes all the foosmb logic centralized and allows new foosmb modules to be self-contained w/o having to hack smbus.c everytime a new smbus driver is added. - Add a new SMB_EINVAL error bit and use it in place of EINVAL to return an error for bad arguments (such as invalid counts for bread and bwrite). - Map SMB bus error bits to EIO in smbus_error(). - Make the smbus driver call bus_generic_probe() and require child drivers such as smb(4) to create device_t's via identify routines. Previously, smbus just created one anonymous device during attach, and if you had multiple drivers that could attach it was just random chance as to which driver got to probe for the sole device_t first. - Add a mutex to the smbus(4) softc and use it in place of dummy splhigh() to protect the 'owner' field and perform necessary synchronization for smbus_request_bus() and smbus_release_bus(). - Change the bread() and bwrite() methods of alpm(4), amdpm(4), and viapm(4) to only perform a single transaction and not try to use a loop of multiple transactions for a large request. The framing and commands to use for a large transaction depend on the upper-layer protocol (such as SSIF for IPMI over SMBus) from what I can tell, and the smb(4) driver never allowed bulk read/writes of more than 32-bytes anyway. The other smb drivers only performed single transactions. - Fix buffer overflows in the bread() methods of ichsmb(4), alpm(4), amdpm(4), amdsmb(4), intpm(4), and nfsmb(4). - Use SMB_xxx errors in viapm(4). - Destroy ichsmb(4)'s mutex after bus_generic_detach() to avoid problems from child devices making smb upcalls that would use the mutex during their detach methods. MFC after: 1 week Reviewed by: jmg (mostly)
2006-09-11 20:52:41 +00:00
viasmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
{
struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
Minor overhaul of SMBus support: - Change smbus_callback() to pass a void * rather than caddr_t. - Change smbus_bread() to pass a pointer to the count and have it be an in/out parameter. The input is the size of the buffer (same as before), but on return it will contain the actual amount of data read back from the bus. Note that this value may be larger than the input value. It is up to the caller to treat this as an error if desired. - Change the SMB_BREAD ioctl to write out the updated struct smbcmd which will contain the actual number of bytes read in the 'count' field. To preserve the previous ABI, the old ioctl value is mapped to SMB_OLD_BREAD which doesn't copy the updated smbcmd back out to userland. I doubt anyone actually used the old BREAD anyway as it was rediculous to do a bulk-read but not tell the using program how much data was actually read. - Make the smbus driver and devclass public in the smbus module and push all the DRIVER_MODULE()'s for attaching the smbus driver to various foosmb drivers out into the foosmb modules. This makes all the foosmb logic centralized and allows new foosmb modules to be self-contained w/o having to hack smbus.c everytime a new smbus driver is added. - Add a new SMB_EINVAL error bit and use it in place of EINVAL to return an error for bad arguments (such as invalid counts for bread and bwrite). - Map SMB bus error bits to EIO in smbus_error(). - Make the smbus driver call bus_generic_probe() and require child drivers such as smb(4) to create device_t's via identify routines. Previously, smbus just created one anonymous device during attach, and if you had multiple drivers that could attach it was just random chance as to which driver got to probe for the sole device_t first. - Add a mutex to the smbus(4) softc and use it in place of dummy splhigh() to protect the 'owner' field and perform necessary synchronization for smbus_request_bus() and smbus_release_bus(). - Change the bread() and bwrite() methods of alpm(4), amdpm(4), and viapm(4) to only perform a single transaction and not try to use a loop of multiple transactions for a large request. The framing and commands to use for a large transaction depend on the upper-layer protocol (such as SSIF for IPMI over SMBus) from what I can tell, and the smb(4) driver never allowed bulk read/writes of more than 32-bytes anyway. The other smb drivers only performed single transactions. - Fix buffer overflows in the bread() methods of ichsmb(4), alpm(4), amdpm(4), amdsmb(4), intpm(4), and nfsmb(4). - Use SMB_xxx errors in viapm(4). - Destroy ichsmb(4)'s mutex after bus_generic_detach() to avoid problems from child devices making smb upcalls that would use the mutex during their detach methods. MFC after: 1 week Reviewed by: jmg (mostly)
2006-09-11 20:52:41 +00:00
u_char data, len, i;
int error;
if (*count < 1 || *count > 32)
return (SMB_EINVAL);
VIAPM_LOCK(viapm);
viapm_clear(viapm);
if (viapm_busy(viapm)) {
VIAPM_UNLOCK(viapm);
Minor overhaul of SMBus support: - Change smbus_callback() to pass a void * rather than caddr_t. - Change smbus_bread() to pass a pointer to the count and have it be an in/out parameter. The input is the size of the buffer (same as before), but on return it will contain the actual amount of data read back from the bus. Note that this value may be larger than the input value. It is up to the caller to treat this as an error if desired. - Change the SMB_BREAD ioctl to write out the updated struct smbcmd which will contain the actual number of bytes read in the 'count' field. To preserve the previous ABI, the old ioctl value is mapped to SMB_OLD_BREAD which doesn't copy the updated smbcmd back out to userland. I doubt anyone actually used the old BREAD anyway as it was rediculous to do a bulk-read but not tell the using program how much data was actually read. - Make the smbus driver and devclass public in the smbus module and push all the DRIVER_MODULE()'s for attaching the smbus driver to various foosmb drivers out into the foosmb modules. This makes all the foosmb logic centralized and allows new foosmb modules to be self-contained w/o having to hack smbus.c everytime a new smbus driver is added. - Add a new SMB_EINVAL error bit and use it in place of EINVAL to return an error for bad arguments (such as invalid counts for bread and bwrite). - Map SMB bus error bits to EIO in smbus_error(). - Make the smbus driver call bus_generic_probe() and require child drivers such as smb(4) to create device_t's via identify routines. Previously, smbus just created one anonymous device during attach, and if you had multiple drivers that could attach it was just random chance as to which driver got to probe for the sole device_t first. - Add a mutex to the smbus(4) softc and use it in place of dummy splhigh() to protect the 'owner' field and perform necessary synchronization for smbus_request_bus() and smbus_release_bus(). - Change the bread() and bwrite() methods of alpm(4), amdpm(4), and viapm(4) to only perform a single transaction and not try to use a loop of multiple transactions for a large request. The framing and commands to use for a large transaction depend on the upper-layer protocol (such as SSIF for IPMI over SMBus) from what I can tell, and the smb(4) driver never allowed bulk read/writes of more than 32-bytes anyway. The other smb drivers only performed single transactions. - Fix buffer overflows in the bread() methods of ichsmb(4), alpm(4), amdpm(4), amdsmb(4), intpm(4), and nfsmb(4). - Use SMB_xxx errors in viapm(4). - Destroy ichsmb(4)'s mutex after bus_generic_detach() to avoid problems from child devices making smb upcalls that would use the mutex during their detach methods. MFC after: 1 week Reviewed by: jmg (mostly)
2006-09-11 20:52:41 +00:00
return (SMB_EBUSY);
}
Minor overhaul of SMBus support: - Change smbus_callback() to pass a void * rather than caddr_t. - Change smbus_bread() to pass a pointer to the count and have it be an in/out parameter. The input is the size of the buffer (same as before), but on return it will contain the actual amount of data read back from the bus. Note that this value may be larger than the input value. It is up to the caller to treat this as an error if desired. - Change the SMB_BREAD ioctl to write out the updated struct smbcmd which will contain the actual number of bytes read in the 'count' field. To preserve the previous ABI, the old ioctl value is mapped to SMB_OLD_BREAD which doesn't copy the updated smbcmd back out to userland. I doubt anyone actually used the old BREAD anyway as it was rediculous to do a bulk-read but not tell the using program how much data was actually read. - Make the smbus driver and devclass public in the smbus module and push all the DRIVER_MODULE()'s for attaching the smbus driver to various foosmb drivers out into the foosmb modules. This makes all the foosmb logic centralized and allows new foosmb modules to be self-contained w/o having to hack smbus.c everytime a new smbus driver is added. - Add a new SMB_EINVAL error bit and use it in place of EINVAL to return an error for bad arguments (such as invalid counts for bread and bwrite). - Map SMB bus error bits to EIO in smbus_error(). - Make the smbus driver call bus_generic_probe() and require child drivers such as smb(4) to create device_t's via identify routines. Previously, smbus just created one anonymous device during attach, and if you had multiple drivers that could attach it was just random chance as to which driver got to probe for the sole device_t first. - Add a mutex to the smbus(4) softc and use it in place of dummy splhigh() to protect the 'owner' field and perform necessary synchronization for smbus_request_bus() and smbus_release_bus(). - Change the bread() and bwrite() methods of alpm(4), amdpm(4), and viapm(4) to only perform a single transaction and not try to use a loop of multiple transactions for a large request. The framing and commands to use for a large transaction depend on the upper-layer protocol (such as SSIF for IPMI over SMBus) from what I can tell, and the smb(4) driver never allowed bulk read/writes of more than 32-bytes anyway. The other smb drivers only performed single transactions. - Fix buffer overflows in the bread() methods of ichsmb(4), alpm(4), amdpm(4), amdsmb(4), intpm(4), and nfsmb(4). - Use SMB_xxx errors in viapm(4). - Destroy ichsmb(4)'s mutex after bus_generic_detach() to avoid problems from child devices making smb upcalls that would use the mutex during their detach methods. MFC after: 1 week Reviewed by: jmg (mostly)
2006-09-11 20:52:41 +00:00
VIAPM_OUTB(SMBHADDR, slave | LSB);
VIAPM_OUTB(SMBHCMD, cmd);
VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BLOCK);
Minor overhaul of SMBus support: - Change smbus_callback() to pass a void * rather than caddr_t. - Change smbus_bread() to pass a pointer to the count and have it be an in/out parameter. The input is the size of the buffer (same as before), but on return it will contain the actual amount of data read back from the bus. Note that this value may be larger than the input value. It is up to the caller to treat this as an error if desired. - Change the SMB_BREAD ioctl to write out the updated struct smbcmd which will contain the actual number of bytes read in the 'count' field. To preserve the previous ABI, the old ioctl value is mapped to SMB_OLD_BREAD which doesn't copy the updated smbcmd back out to userland. I doubt anyone actually used the old BREAD anyway as it was rediculous to do a bulk-read but not tell the using program how much data was actually read. - Make the smbus driver and devclass public in the smbus module and push all the DRIVER_MODULE()'s for attaching the smbus driver to various foosmb drivers out into the foosmb modules. This makes all the foosmb logic centralized and allows new foosmb modules to be self-contained w/o having to hack smbus.c everytime a new smbus driver is added. - Add a new SMB_EINVAL error bit and use it in place of EINVAL to return an error for bad arguments (such as invalid counts for bread and bwrite). - Map SMB bus error bits to EIO in smbus_error(). - Make the smbus driver call bus_generic_probe() and require child drivers such as smb(4) to create device_t's via identify routines. Previously, smbus just created one anonymous device during attach, and if you had multiple drivers that could attach it was just random chance as to which driver got to probe for the sole device_t first. - Add a mutex to the smbus(4) softc and use it in place of dummy splhigh() to protect the 'owner' field and perform necessary synchronization for smbus_request_bus() and smbus_release_bus(). - Change the bread() and bwrite() methods of alpm(4), amdpm(4), and viapm(4) to only perform a single transaction and not try to use a loop of multiple transactions for a large request. The framing and commands to use for a large transaction depend on the upper-layer protocol (such as SSIF for IPMI over SMBus) from what I can tell, and the smb(4) driver never allowed bulk read/writes of more than 32-bytes anyway. The other smb drivers only performed single transactions. - Fix buffer overflows in the bread() methods of ichsmb(4), alpm(4), amdpm(4), amdsmb(4), intpm(4), and nfsmb(4). - Use SMB_xxx errors in viapm(4). - Destroy ichsmb(4)'s mutex after bus_generic_detach() to avoid problems from child devices making smb upcalls that would use the mutex during their detach methods. MFC after: 1 week Reviewed by: jmg (mostly)
2006-09-11 20:52:41 +00:00
if ((error = viapm_wait(viapm)) != SMB_ENOERR)
goto error;
Minor overhaul of SMBus support: - Change smbus_callback() to pass a void * rather than caddr_t. - Change smbus_bread() to pass a pointer to the count and have it be an in/out parameter. The input is the size of the buffer (same as before), but on return it will contain the actual amount of data read back from the bus. Note that this value may be larger than the input value. It is up to the caller to treat this as an error if desired. - Change the SMB_BREAD ioctl to write out the updated struct smbcmd which will contain the actual number of bytes read in the 'count' field. To preserve the previous ABI, the old ioctl value is mapped to SMB_OLD_BREAD which doesn't copy the updated smbcmd back out to userland. I doubt anyone actually used the old BREAD anyway as it was rediculous to do a bulk-read but not tell the using program how much data was actually read. - Make the smbus driver and devclass public in the smbus module and push all the DRIVER_MODULE()'s for attaching the smbus driver to various foosmb drivers out into the foosmb modules. This makes all the foosmb logic centralized and allows new foosmb modules to be self-contained w/o having to hack smbus.c everytime a new smbus driver is added. - Add a new SMB_EINVAL error bit and use it in place of EINVAL to return an error for bad arguments (such as invalid counts for bread and bwrite). - Map SMB bus error bits to EIO in smbus_error(). - Make the smbus driver call bus_generic_probe() and require child drivers such as smb(4) to create device_t's via identify routines. Previously, smbus just created one anonymous device during attach, and if you had multiple drivers that could attach it was just random chance as to which driver got to probe for the sole device_t first. - Add a mutex to the smbus(4) softc and use it in place of dummy splhigh() to protect the 'owner' field and perform necessary synchronization for smbus_request_bus() and smbus_release_bus(). - Change the bread() and bwrite() methods of alpm(4), amdpm(4), and viapm(4) to only perform a single transaction and not try to use a loop of multiple transactions for a large request. The framing and commands to use for a large transaction depend on the upper-layer protocol (such as SSIF for IPMI over SMBus) from what I can tell, and the smb(4) driver never allowed bulk read/writes of more than 32-bytes anyway. The other smb drivers only performed single transactions. - Fix buffer overflows in the bread() methods of ichsmb(4), alpm(4), amdpm(4), amdsmb(4), intpm(4), and nfsmb(4). - Use SMB_xxx errors in viapm(4). - Destroy ichsmb(4)'s mutex after bus_generic_detach() to avoid problems from child devices making smb upcalls that would use the mutex during their detach methods. MFC after: 1 week Reviewed by: jmg (mostly)
2006-09-11 20:52:41 +00:00
len = VIAPM_INB(SMBHDATA0);
i = VIAPM_INB(SMBHCTRL); /* reset counter */
Minor overhaul of SMBus support: - Change smbus_callback() to pass a void * rather than caddr_t. - Change smbus_bread() to pass a pointer to the count and have it be an in/out parameter. The input is the size of the buffer (same as before), but on return it will contain the actual amount of data read back from the bus. Note that this value may be larger than the input value. It is up to the caller to treat this as an error if desired. - Change the SMB_BREAD ioctl to write out the updated struct smbcmd which will contain the actual number of bytes read in the 'count' field. To preserve the previous ABI, the old ioctl value is mapped to SMB_OLD_BREAD which doesn't copy the updated smbcmd back out to userland. I doubt anyone actually used the old BREAD anyway as it was rediculous to do a bulk-read but not tell the using program how much data was actually read. - Make the smbus driver and devclass public in the smbus module and push all the DRIVER_MODULE()'s for attaching the smbus driver to various foosmb drivers out into the foosmb modules. This makes all the foosmb logic centralized and allows new foosmb modules to be self-contained w/o having to hack smbus.c everytime a new smbus driver is added. - Add a new SMB_EINVAL error bit and use it in place of EINVAL to return an error for bad arguments (such as invalid counts for bread and bwrite). - Map SMB bus error bits to EIO in smbus_error(). - Make the smbus driver call bus_generic_probe() and require child drivers such as smb(4) to create device_t's via identify routines. Previously, smbus just created one anonymous device during attach, and if you had multiple drivers that could attach it was just random chance as to which driver got to probe for the sole device_t first. - Add a mutex to the smbus(4) softc and use it in place of dummy splhigh() to protect the 'owner' field and perform necessary synchronization for smbus_request_bus() and smbus_release_bus(). - Change the bread() and bwrite() methods of alpm(4), amdpm(4), and viapm(4) to only perform a single transaction and not try to use a loop of multiple transactions for a large request. The framing and commands to use for a large transaction depend on the upper-layer protocol (such as SSIF for IPMI over SMBus) from what I can tell, and the smb(4) driver never allowed bulk read/writes of more than 32-bytes anyway. The other smb drivers only performed single transactions. - Fix buffer overflows in the bread() methods of ichsmb(4), alpm(4), amdpm(4), amdsmb(4), intpm(4), and nfsmb(4). - Use SMB_xxx errors in viapm(4). - Destroy ichsmb(4)'s mutex after bus_generic_detach() to avoid problems from child devices making smb upcalls that would use the mutex during their detach methods. MFC after: 1 week Reviewed by: jmg (mostly)
2006-09-11 20:52:41 +00:00
/* read the 32-byte internal buffer */
for (i = 0; i < len; i++) {
data = VIAPM_INB(SMBHBLOCK);
if (i < *count)
buf[i] = data;
DELAY(2);
}
Minor overhaul of SMBus support: - Change smbus_callback() to pass a void * rather than caddr_t. - Change smbus_bread() to pass a pointer to the count and have it be an in/out parameter. The input is the size of the buffer (same as before), but on return it will contain the actual amount of data read back from the bus. Note that this value may be larger than the input value. It is up to the caller to treat this as an error if desired. - Change the SMB_BREAD ioctl to write out the updated struct smbcmd which will contain the actual number of bytes read in the 'count' field. To preserve the previous ABI, the old ioctl value is mapped to SMB_OLD_BREAD which doesn't copy the updated smbcmd back out to userland. I doubt anyone actually used the old BREAD anyway as it was rediculous to do a bulk-read but not tell the using program how much data was actually read. - Make the smbus driver and devclass public in the smbus module and push all the DRIVER_MODULE()'s for attaching the smbus driver to various foosmb drivers out into the foosmb modules. This makes all the foosmb logic centralized and allows new foosmb modules to be self-contained w/o having to hack smbus.c everytime a new smbus driver is added. - Add a new SMB_EINVAL error bit and use it in place of EINVAL to return an error for bad arguments (such as invalid counts for bread and bwrite). - Map SMB bus error bits to EIO in smbus_error(). - Make the smbus driver call bus_generic_probe() and require child drivers such as smb(4) to create device_t's via identify routines. Previously, smbus just created one anonymous device during attach, and if you had multiple drivers that could attach it was just random chance as to which driver got to probe for the sole device_t first. - Add a mutex to the smbus(4) softc and use it in place of dummy splhigh() to protect the 'owner' field and perform necessary synchronization for smbus_request_bus() and smbus_release_bus(). - Change the bread() and bwrite() methods of alpm(4), amdpm(4), and viapm(4) to only perform a single transaction and not try to use a loop of multiple transactions for a large request. The framing and commands to use for a large transaction depend on the upper-layer protocol (such as SSIF for IPMI over SMBus) from what I can tell, and the smb(4) driver never allowed bulk read/writes of more than 32-bytes anyway. The other smb drivers only performed single transactions. - Fix buffer overflows in the bread() methods of ichsmb(4), alpm(4), amdpm(4), amdsmb(4), intpm(4), and nfsmb(4). - Use SMB_xxx errors in viapm(4). - Destroy ichsmb(4)'s mutex after bus_generic_detach() to avoid problems from child devices making smb upcalls that would use the mutex during their detach methods. MFC after: 1 week Reviewed by: jmg (mostly)
2006-09-11 20:52:41 +00:00
*count = len;
error:
Minor overhaul of SMBus support: - Change smbus_callback() to pass a void * rather than caddr_t. - Change smbus_bread() to pass a pointer to the count and have it be an in/out parameter. The input is the size of the buffer (same as before), but on return it will contain the actual amount of data read back from the bus. Note that this value may be larger than the input value. It is up to the caller to treat this as an error if desired. - Change the SMB_BREAD ioctl to write out the updated struct smbcmd which will contain the actual number of bytes read in the 'count' field. To preserve the previous ABI, the old ioctl value is mapped to SMB_OLD_BREAD which doesn't copy the updated smbcmd back out to userland. I doubt anyone actually used the old BREAD anyway as it was rediculous to do a bulk-read but not tell the using program how much data was actually read. - Make the smbus driver and devclass public in the smbus module and push all the DRIVER_MODULE()'s for attaching the smbus driver to various foosmb drivers out into the foosmb modules. This makes all the foosmb logic centralized and allows new foosmb modules to be self-contained w/o having to hack smbus.c everytime a new smbus driver is added. - Add a new SMB_EINVAL error bit and use it in place of EINVAL to return an error for bad arguments (such as invalid counts for bread and bwrite). - Map SMB bus error bits to EIO in smbus_error(). - Make the smbus driver call bus_generic_probe() and require child drivers such as smb(4) to create device_t's via identify routines. Previously, smbus just created one anonymous device during attach, and if you had multiple drivers that could attach it was just random chance as to which driver got to probe for the sole device_t first. - Add a mutex to the smbus(4) softc and use it in place of dummy splhigh() to protect the 'owner' field and perform necessary synchronization for smbus_request_bus() and smbus_release_bus(). - Change the bread() and bwrite() methods of alpm(4), amdpm(4), and viapm(4) to only perform a single transaction and not try to use a loop of multiple transactions for a large request. The framing and commands to use for a large transaction depend on the upper-layer protocol (such as SSIF for IPMI over SMBus) from what I can tell, and the smb(4) driver never allowed bulk read/writes of more than 32-bytes anyway. The other smb drivers only performed single transactions. - Fix buffer overflows in the bread() methods of ichsmb(4), alpm(4), amdpm(4), amdsmb(4), intpm(4), and nfsmb(4). - Use SMB_xxx errors in viapm(4). - Destroy ichsmb(4)'s mutex after bus_generic_detach() to avoid problems from child devices making smb upcalls that would use the mutex during their detach methods. MFC after: 1 week Reviewed by: jmg (mostly)
2006-09-11 20:52:41 +00:00
VIAPM_DEBUG(printf("viapm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, *count, cmd, error));
VIAPM_UNLOCK(viapm);
return (error);
}
static device_method_t viapm_methods[] = {
/* device interface */
DEVMETHOD(device_probe, viapm_586b_probe),
DEVMETHOD(device_attach, viapm_586b_attach),
DEVMETHOD(device_detach, viapm_586b_detach),
/* iicbb interface */
DEVMETHOD(iicbb_callback, viabb_callback),
DEVMETHOD(iicbb_setscl, viabb_setscl),
DEVMETHOD(iicbb_setsda, viabb_setsda),
DEVMETHOD(iicbb_getscl, viabb_getscl),
DEVMETHOD(iicbb_getsda, viabb_getsda),
DEVMETHOD(iicbb_reset, viabb_reset),
/* Bus interface */
DEVMETHOD(bus_print_child, bus_generic_print_child),
DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
DEVMETHOD(bus_release_resource, bus_generic_release_resource),
DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
{ 0, 0 }
};
static driver_t viapm_driver = {
"viapm",
viapm_methods,
sizeof(struct viapm_softc),
};
static device_method_t viapropm_methods[] = {
/* device interface */
DEVMETHOD(device_probe, viapm_pro_probe),
DEVMETHOD(device_attach, viapm_pro_attach),
DEVMETHOD(device_detach, viapm_pro_detach),
/* smbus interface */
DEVMETHOD(smbus_callback, viasmb_callback),
DEVMETHOD(smbus_quick, viasmb_quick),
DEVMETHOD(smbus_sendb, viasmb_sendb),
DEVMETHOD(smbus_recvb, viasmb_recvb),
DEVMETHOD(smbus_writeb, viasmb_writeb),
DEVMETHOD(smbus_readb, viasmb_readb),
DEVMETHOD(smbus_writew, viasmb_writew),
DEVMETHOD(smbus_readw, viasmb_readw),
DEVMETHOD(smbus_bwrite, viasmb_bwrite),
DEVMETHOD(smbus_bread, viasmb_bread),
/* Bus interface */
DEVMETHOD(bus_print_child, bus_generic_print_child),
DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource),
DEVMETHOD(bus_release_resource, bus_generic_release_resource),
DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
{ 0, 0 }
};
static driver_t viapropm_driver = {
"viapropm",
viapropm_methods,
sizeof(struct viapm_softc),
};
DRIVER_MODULE(viapm, pci, viapm_driver, viapm_devclass, 0, 0);
DRIVER_MODULE(viapropm, pci, viapropm_driver, viapropm_devclass, 0, 0);
Minor overhaul of SMBus support: - Change smbus_callback() to pass a void * rather than caddr_t. - Change smbus_bread() to pass a pointer to the count and have it be an in/out parameter. The input is the size of the buffer (same as before), but on return it will contain the actual amount of data read back from the bus. Note that this value may be larger than the input value. It is up to the caller to treat this as an error if desired. - Change the SMB_BREAD ioctl to write out the updated struct smbcmd which will contain the actual number of bytes read in the 'count' field. To preserve the previous ABI, the old ioctl value is mapped to SMB_OLD_BREAD which doesn't copy the updated smbcmd back out to userland. I doubt anyone actually used the old BREAD anyway as it was rediculous to do a bulk-read but not tell the using program how much data was actually read. - Make the smbus driver and devclass public in the smbus module and push all the DRIVER_MODULE()'s for attaching the smbus driver to various foosmb drivers out into the foosmb modules. This makes all the foosmb logic centralized and allows new foosmb modules to be self-contained w/o having to hack smbus.c everytime a new smbus driver is added. - Add a new SMB_EINVAL error bit and use it in place of EINVAL to return an error for bad arguments (such as invalid counts for bread and bwrite). - Map SMB bus error bits to EIO in smbus_error(). - Make the smbus driver call bus_generic_probe() and require child drivers such as smb(4) to create device_t's via identify routines. Previously, smbus just created one anonymous device during attach, and if you had multiple drivers that could attach it was just random chance as to which driver got to probe for the sole device_t first. - Add a mutex to the smbus(4) softc and use it in place of dummy splhigh() to protect the 'owner' field and perform necessary synchronization for smbus_request_bus() and smbus_release_bus(). - Change the bread() and bwrite() methods of alpm(4), amdpm(4), and viapm(4) to only perform a single transaction and not try to use a loop of multiple transactions for a large request. The framing and commands to use for a large transaction depend on the upper-layer protocol (such as SSIF for IPMI over SMBus) from what I can tell, and the smb(4) driver never allowed bulk read/writes of more than 32-bytes anyway. The other smb drivers only performed single transactions. - Fix buffer overflows in the bread() methods of ichsmb(4), alpm(4), amdpm(4), amdsmb(4), intpm(4), and nfsmb(4). - Use SMB_xxx errors in viapm(4). - Destroy ichsmb(4)'s mutex after bus_generic_detach() to avoid problems from child devices making smb upcalls that would use the mutex during their detach methods. MFC after: 1 week Reviewed by: jmg (mostly)
2006-09-11 20:52:41 +00:00
DRIVER_MODULE(smbus, viapropm, smbus_driver, smbus_devclass, 0, 0);
MODULE_DEPEND(viapm, pci, 1, 1, 1);
MODULE_DEPEND(viapropm, pci, 1, 1, 1);
MODULE_DEPEND(viapm, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER);
MODULE_DEPEND(viapropm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
MODULE_VERSION(viapm, 1);
#ifdef DEV_ISA
DRIVER_MODULE(isa, viapm, isa_driver, isa_devclass, 0, 0);
DRIVER_MODULE(isa, viapropm, isa_driver, isa_devclass, 0, 0);
MODULE_DEPEND(viapm, isa, 1, 1, 1);
MODULE_DEPEND(viapropm, isa, 1, 1, 1);
#endif