diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-22 19:36:42 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-22 19:36:42 -0700 |
commit | b9da0571050c09863e59f94d0b8594a290d61b88 (patch) | |
tree | 3632c4fee768db9a27a5c872bd42133692e2f3d0 /drivers/misc | |
parent | f8cae0f03f75adb54b1d48ddbc90f84a1f5de186 (diff) | |
parent | 5abd935661e01289ba143c3b2c1ba300c65bcc5f (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6: (31 commits)
driver core: Display error codes when class suspend fails
Driver core: Add section count to memory_block struct
Driver core: Add mutex for adding/removing memory blocks
Driver core: Move find_memory_block routine
hpilo: Despecificate driver from iLO generation
driver core: Convert link_mem_sections to use find_memory_block_hinted.
driver core: Introduce find_memory_block_hinted which utilizes kset_find_obj_hinted.
kobject: Introduce kset_find_obj_hinted.
driver core: fix build for CONFIG_BLOCK not enabled
driver-core: base: change to new flag variable
sysfs: only access bin file vm_ops with the active lock
sysfs: Fail bin file mmap if vma close is implemented.
FW_LOADER: fix kconfig dependency warning on HOTPLUG
uio: Statically allocate uio_class and use class .dev_attrs.
uio: Support 2^MINOR_BITS minors
uio: Cleanup irq handling.
uio: Don't clear driver data
uio: Fix lack of locking in init_uio_class
SYSFS: Allow boot time switching between deprecated and modern sysfs layout
driver core: remove CONFIG_SYSFS_DEPRECATED_V2 but keep it for block devices
...
Diffstat (limited to 'drivers/misc')
-rw-r--r-- | drivers/misc/Kconfig | 22 | ||||
-rw-r--r-- | drivers/misc/Makefile | 1 | ||||
-rw-r--r-- | drivers/misc/hpilo.c | 2 | ||||
-rw-r--r-- | drivers/misc/pch_phub.c | 717 |
4 files changed, 736 insertions, 6 deletions
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index b7433126074..db2fbe2d414 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -248,15 +248,15 @@ config CS5535_CLOCK_EVENT_SRC generic PIT, and are suitable for use as high-res timers. config HP_ILO - tristate "Channel interface driver for HP iLO/iLO2 processor" + tristate "Channel interface driver for the HP iLO processor" depends on PCI default n help The channel interface driver allows applications to communicate - with iLO/iLO2 management processors present on HP ProLiant - servers. Upon loading, the driver creates /dev/hpilo/dXccbN files, - which can be used to gather data from the management processor, - via read and write system calls. + with iLO management processors present on HP ProLiant servers. + Upon loading, the driver creates /dev/hpilo/dXccbN files, which + can be used to gather data from the management processor, via + read and write system calls. To compile this driver as a module, choose M here: the module will be called hpilo. @@ -390,6 +390,18 @@ config BMP085 To compile this driver as a module, choose M here: the module will be called bmp085. +config PCH_PHUB + tristate "PCH Packet Hub of Intel Topcliff" + depends on PCI + help + This driver is for PCH(Platform controller Hub) PHUB(Packet Hub) of + Intel Topcliff which is an IOH(Input/Output Hub) for x86 embedded + processor. The Topcliff has MAC address and Option ROM data in SROM. + This driver can access MAC address and Option ROM data in SROM. + + To compile this driver as a module, choose M here: the module will + be called pch_phub. + source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 42eab95cde2..9f2986b4da2 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -35,3 +35,4 @@ obj-y += eeprom/ obj-y += cb710/ obj-$(CONFIG_VMWARE_BALLOON) += vmw_balloon.o obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o +obj-$(CONFIG_PCH_PHUB) += pch_phub.o diff --git a/drivers/misc/hpilo.c b/drivers/misc/hpilo.c index 69c1f2fca14..fffc227181b 100644 --- a/drivers/misc/hpilo.c +++ b/drivers/misc/hpilo.c @@ -1,5 +1,5 @@ /* - * Driver for HP iLO/iLO2 management processor. + * Driver for the HP iLO management processor. * * Copyright (C) 2008 Hewlett-Packard Development Company, L.P. * David Altobelli <david.altobelli@hp.com> diff --git a/drivers/misc/pch_phub.c b/drivers/misc/pch_phub.c new file mode 100644 index 00000000000..744b804aca1 --- /dev/null +++ b/drivers/misc/pch_phub.c @@ -0,0 +1,717 @@ +/* + * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/fs.h> +#include <linux/uaccess.h> +#include <linux/string.h> +#include <linux/pci.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/mutex.h> +#include <linux/if_ether.h> +#include <linux/ctype.h> + +#define PHUB_STATUS 0x00 /* Status Register offset */ +#define PHUB_CONTROL 0x04 /* Control Register offset */ +#define PHUB_TIMEOUT 0x05 /* Time out value for Status Register */ +#define PCH_PHUB_ROM_WRITE_ENABLE 0x01 /* Enabling for writing ROM */ +#define PCH_PHUB_ROM_WRITE_DISABLE 0x00 /* Disabling for writing ROM */ +#define PCH_PHUB_ROM_START_ADDR 0x14 /* ROM data area start address offset */ + +/* MAX number of INT_REDUCE_CONTROL registers */ +#define MAX_NUM_INT_REDUCE_CONTROL_REG 128 +#define PCI_DEVICE_ID_PCH1_PHUB 0x8801 +#define PCH_MINOR_NOS 1 +#define CLKCFG_CAN_50MHZ 0x12000000 +#define CLKCFG_CANCLK_MASK 0xFF000000 + +/* SROM ACCESS Macro */ +#define PCH_WORD_ADDR_MASK (~((1 << 2) - 1)) + +/* Registers address offset */ +#define PCH_PHUB_ID_REG 0x0000 +#define PCH_PHUB_QUEUE_PRI_VAL_REG 0x0004 +#define PCH_PHUB_RC_QUEUE_MAXSIZE_REG 0x0008 +#define PCH_PHUB_BRI_QUEUE_MAXSIZE_REG 0x000C +#define PCH_PHUB_COMP_RESP_TIMEOUT_REG 0x0010 +#define PCH_PHUB_BUS_SLAVE_CONTROL_REG 0x0014 +#define PCH_PHUB_DEADLOCK_AVOID_TYPE_REG 0x0018 +#define PCH_PHUB_INTPIN_REG_WPERMIT_REG0 0x0020 +#define PCH_PHUB_INTPIN_REG_WPERMIT_REG1 0x0024 +#define PCH_PHUB_INTPIN_REG_WPERMIT_REG2 0x0028 +#define PCH_PHUB_INTPIN_REG_WPERMIT_REG3 0x002C +#define PCH_PHUB_INT_REDUCE_CONTROL_REG_BASE 0x0040 +#define CLKCFG_REG_OFFSET 0x500 + +#define PCH_PHUB_OROM_SIZE 15360 + +/** + * struct pch_phub_reg - PHUB register structure + * @phub_id_reg: PHUB_ID register val + * @q_pri_val_reg: QUEUE_PRI_VAL register val + * @rc_q_maxsize_reg: RC_QUEUE_MAXSIZE register val + * @bri_q_maxsize_reg: BRI_QUEUE_MAXSIZE register val + * @comp_resp_timeout_reg: COMP_RESP_TIMEOUT register val + * @bus_slave_control_reg: BUS_SLAVE_CONTROL_REG register val + * @deadlock_avoid_type_reg: DEADLOCK_AVOID_TYPE register val + * @intpin_reg_wpermit_reg0: INTPIN_REG_WPERMIT register 0 val + * @intpin_reg_wpermit_reg1: INTPIN_REG_WPERMIT register 1 val + * @intpin_reg_wpermit_reg2: INTPIN_REG_WPERMIT register 2 val + * @intpin_reg_wpermit_reg3: INTPIN_REG_WPERMIT register 3 val + * @int_reduce_control_reg: INT_REDUCE_CONTROL registers val + * @clkcfg_reg: CLK CFG register val + * @pch_phub_base_address: Register base address + * @pch_phub_extrom_base_address: external rom base address + */ +struct pch_phub_reg { + u32 phub_id_reg; + u32 q_pri_val_reg; + u32 rc_q_maxsize_reg; + u32 bri_q_maxsize_reg; + u32 comp_resp_timeout_reg; + u32 bus_slave_control_reg; + u32 deadlock_avoid_type_reg; + u32 intpin_reg_wpermit_reg0; + u32 intpin_reg_wpermit_reg1; + u32 intpin_reg_wpermit_reg2; + u32 intpin_reg_wpermit_reg3; + u32 int_reduce_control_reg[MAX_NUM_INT_REDUCE_CONTROL_REG]; + u32 clkcfg_reg; + void __iomem *pch_phub_base_address; + void __iomem *pch_phub_extrom_base_address; +}; + +/* SROM SPEC for MAC address assignment offset */ +static const int pch_phub_mac_offset[ETH_ALEN] = {0x3, 0x2, 0x1, 0x0, 0xb, 0xa}; + +static DEFINE_MUTEX(pch_phub_mutex); + +/** + * pch_phub_read_modify_write_reg() - Reading modifying and writing register + * @reg_addr_offset: Register offset address value. + * @data: Writing value. + * @mask: Mask value. + */ +static void pch_phub_read_modify_write_reg(struct pch_phub_reg *chip, + unsigned int reg_addr_offset, + unsigned int data, unsigned int mask) +{ + void __iomem *reg_addr = chip->pch_phub_base_address + reg_addr_offset; + iowrite32(((ioread32(reg_addr) & ~mask)) | data, reg_addr); +} + +/* pch_phub_save_reg_conf - saves register configuration */ +static void pch_phub_save_reg_conf(struct pci_dev *pdev) +{ + unsigned int i; + struct pch_phub_reg *chip = pci_get_drvdata(pdev); + + void __iomem *p = chip->pch_phub_base_address; + + chip->phub_id_reg = ioread32(p + PCH_PHUB_ID_REG); + chip->q_pri_val_reg = ioread32(p + PCH_PHUB_QUEUE_PRI_VAL_REG); + chip->rc_q_maxsize_reg = ioread32(p + PCH_PHUB_RC_QUEUE_MAXSIZE_REG); + chip->bri_q_maxsize_reg = ioread32(p + PCH_PHUB_BRI_QUEUE_MAXSIZE_REG); + chip->comp_resp_timeout_reg = + ioread32(p + PCH_PHUB_COMP_RESP_TIMEOUT_REG); + chip->bus_slave_control_reg = + ioread32(p + PCH_PHUB_BUS_SLAVE_CONTROL_REG); + chip->deadlock_avoid_type_reg = + ioread32(p + PCH_PHUB_DEADLOCK_AVOID_TYPE_REG); + chip->intpin_reg_wpermit_reg0 = + ioread32(p + PCH_PHUB_INTPIN_REG_WPERMIT_REG0); + chip->intpin_reg_wpermit_reg1 = + ioread32(p + PCH_PHUB_INTPIN_REG_WPERMIT_REG1); + chip->intpin_reg_wpermit_reg2 = + ioread32(p + PCH_PHUB_INTPIN_REG_WPERMIT_REG2); + chip->intpin_reg_wpermit_reg3 = + ioread32(p + PCH_PHUB_INTPIN_REG_WPERMIT_REG3); + dev_dbg(&pdev->dev, "%s : " + "chip->phub_id_reg=%x, " + "chip->q_pri_val_reg=%x, " + "chip->rc_q_maxsize_reg=%x, " + "chip->bri_q_maxsize_reg=%x, " + "chip->comp_resp_timeout_reg=%x, " + "chip->bus_slave_control_reg=%x, " + "chip->deadlock_avoid_type_reg=%x, " + "chip->intpin_reg_wpermit_reg0=%x, " + "chip->intpin_reg_wpermit_reg1=%x, " + "chip->intpin_reg_wpermit_reg2=%x, " + "chip->intpin_reg_wpermit_reg3=%x\n", __func__, + chip->phub_id_reg, + chip->q_pri_val_reg, + chip->rc_q_maxsize_reg, + chip->bri_q_maxsize_reg, + chip->comp_resp_timeout_reg, + chip->bus_slave_control_reg, + chip->deadlock_avoid_type_reg, + chip->intpin_reg_wpermit_reg0, + chip->intpin_reg_wpermit_reg1, + chip->intpin_reg_wpermit_reg2, + chip->intpin_reg_wpermit_reg3); + for (i = 0; i < MAX_NUM_INT_REDUCE_CONTROL_REG; i++) { + chip->int_reduce_control_reg[i] = + ioread32(p + PCH_PHUB_INT_REDUCE_CONTROL_REG_BASE + 4 * i); + dev_dbg(&pdev->dev, "%s : " + "chip->int_reduce_control_reg[%d]=%x\n", + __func__, i, chip->int_reduce_control_reg[i]); + } + chip->clkcfg_reg = ioread32(p + CLKCFG_REG_OFFSET); +} + +/* pch_phub_restore_reg_conf - restore register configuration */ +static void pch_phub_restore_reg_conf(struct pci_dev *pdev) +{ + unsigned int i; + struct pch_phub_reg *chip = pci_get_drvdata(pdev); + void __iomem *p; + p = chip->pch_phub_base_address; + + iowrite32(chip->phub_id_reg, p + PCH_PHUB_ID_REG); + iowrite32(chip->q_pri_val_reg, p + PCH_PHUB_QUEUE_PRI_VAL_REG); + iowrite32(chip->rc_q_maxsize_reg, p + PCH_PHUB_RC_QUEUE_MAXSIZE_REG); + iowrite32(chip->bri_q_maxsize_reg, p + PCH_PHUB_BRI_QUEUE_MAXSIZE_REG); + iowrite32(chip->comp_resp_timeout_reg, + p + PCH_PHUB_COMP_RESP_TIMEOUT_REG); + iowrite32(chip->bus_slave_control_reg, + p + PCH_PHUB_BUS_SLAVE_CONTROL_REG); + iowrite32(chip->deadlock_avoid_type_reg, + p + PCH_PHUB_DEADLOCK_AVOID_TYPE_REG); + iowrite32(chip->intpin_reg_wpermit_reg0, + p + PCH_PHUB_INTPIN_REG_WPERMIT_REG0); + iowrite32(chip->intpin_reg_wpermit_reg1, + p + PCH_PHUB_INTPIN_REG_WPERMIT_REG1); + iowrite32(chip->intpin_reg_wpermit_reg2, + p + PCH_PHUB_INTPIN_REG_WPERMIT_REG2); + iowrite32(chip->intpin_reg_wpermit_reg3, + p + PCH_PHUB_INTPIN_REG_WPERMIT_REG3); + dev_dbg(&pdev->dev, "%s : " + "chip->phub_id_reg=%x, " + "chip->q_pri_val_reg=%x, " + "chip->rc_q_maxsize_reg=%x, " + "chip->bri_q_maxsize_reg=%x, " + "chip->comp_resp_timeout_reg=%x, " + "chip->bus_slave_control_reg=%x, " + "chip->deadlock_avoid_type_reg=%x, " + "chip->intpin_reg_wpermit_reg0=%x, " + "chip->intpin_reg_wpermit_reg1=%x, " + "chip->intpin_reg_wpermit_reg2=%x, " + "chip->intpin_reg_wpermit_reg3=%x\n", __func__, + chip->phub_id_reg, + chip->q_pri_val_reg, + chip->rc_q_maxsize_reg, + chip->bri_q_maxsize_reg, + chip->comp_resp_timeout_reg, + chip->bus_slave_control_reg, + chip->deadlock_avoid_type_reg, + chip->intpin_reg_wpermit_reg0, + chip->intpin_reg_wpermit_reg1, + chip->intpin_reg_wpermit_reg2, + chip->intpin_reg_wpermit_reg3); + for (i = 0; i < MAX_NUM_INT_REDUCE_CONTROL_REG; i++) { + iowrite32(chip->int_reduce_control_reg[i], + p + PCH_PHUB_INT_REDUCE_CONTROL_REG_BASE + 4 * i); + dev_dbg(&pdev->dev, "%s : " + "chip->int_reduce_control_reg[%d]=%x\n", + __func__, i, chip->int_reduce_control_reg[i]); + } + + iowrite32(chip->clkcfg_reg, p + CLKCFG_REG_OFFSET); +} + +/** + * pch_phub_read_serial_rom() - Reading Serial ROM + * @offset_address: Serial ROM offset address to read. + * @data: Read buffer for specified Serial ROM value. + */ +static void pch_phub_read_serial_rom(struct pch_phub_reg *chip, + unsigned int offset_address, u8 *data) +{ + void __iomem *mem_addr = chip->pch_phub_extrom_base_address + + offset_address; + + *data = ioread8(mem_addr); +} + +/** + * pch_phub_write_serial_rom() - Writing Serial ROM + * @offset_address: Serial ROM offset address. + * @data: Serial ROM value to write. + */ +static int pch_phub_write_serial_rom(struct pch_phub_reg *chip, + unsigned int offset_address, u8 data) +{ + void __iomem *mem_addr = chip->pch_phub_extrom_base_address + + (offset_address & PCH_WORD_ADDR_MASK); + int i; + unsigned int word_data; + unsigned int pos; + unsigned int mask; + pos = (offset_address % 4) * 8; + mask = ~(0xFF << pos); + + iowrite32(PCH_PHUB_ROM_WRITE_ENABLE, + chip->pch_phub_extrom_base_address + PHUB_CONTROL); + + word_data = ioread32(mem_addr); + iowrite32((word_data & mask) | (u32)data << pos, mem_addr); + + i = 0; + while (ioread8(chip->pch_phub_extrom_base_address + + PHUB_STATUS) != 0x00) { + msleep(1); + if (i == PHUB_TIMEOUT) + return -ETIMEDOUT; + i++; + } + + iowrite32(PCH_PHUB_ROM_WRITE_DISABLE, + chip->pch_phub_extrom_base_address + PHUB_CONTROL); + + return 0; +} + +/** + * pch_phub_read_serial_rom_val() - Read Serial ROM value + * @offset_address: Serial ROM address offset value. + * @data: Serial ROM value to read. + */ +static void pch_phub_read_serial_rom_val(struct pch_phub_reg *chip, + unsigned int offset_address, u8 *data) +{ + unsigned int mem_addr; + + mem_addr = PCH_PHUB_ROM_START_ADDR + + pch_phub_mac_offset[offset_address]; + + pch_phub_read_serial_rom(chip, mem_addr, data); +} + +/** + * pch_phub_write_serial_rom_val() - writing Serial ROM value + * @offset_address: Serial ROM address offset value. + * @data: Serial ROM value. + */ +static int pch_phub_write_serial_rom_val(struct pch_phub_reg *chip, + unsigned int offset_address, u8 data) +{ + int retval; + unsigned int mem_addr; + + mem_addr = PCH_PHUB_ROM_START_ADDR + + pch_phub_mac_offset[offset_address]; + + retval = pch_phub_write_serial_rom(chip, mem_addr, data); + + return retval; +} + +/* pch_phub_gbe_serial_rom_conf - makes Serial ROM header format configuration + * for Gigabit Ethernet MAC address + */ +static int pch_phub_gbe_serial_rom_conf(struct pch_phub_reg *chip) +{ + int retval; + + retval = pch_phub_write_serial_rom(chip, 0x0b, 0xbc); + retval |= pch_phub_write_serial_rom(chip, 0x0a, 0x10); + retval |= pch_phub_write_serial_rom(chip, 0x09, 0x01); + retval |= pch_phub_write_serial_rom(chip, 0x08, 0x02); + + retval |= pch_phub_write_serial_rom(chip, 0x0f, 0x00); + retval |= pch_phub_write_serial_rom(chip, 0x0e, 0x00); + retval |= pch_phub_write_serial_rom(chip, 0x0d, 0x00); + retval |= pch_phub_write_serial_rom(chip, 0x0c, 0x80); + + retval |= pch_phub_write_serial_rom(chip, 0x13, 0xbc); + retval |= pch_phub_write_serial_rom(chip, 0x12, 0x10); + retval |= pch_phub_write_serial_rom(chip, 0x11, 0x01); + retval |= pch_phub_write_serial_rom(chip, 0x10, 0x18); + + retval |= pch_phub_write_serial_rom(chip, 0x1b, 0xbc); + retval |= pch_phub_write_serial_rom(chip, 0x1a, 0x10); + retval |= pch_phub_write_serial_rom(chip, 0x19, 0x01); + retval |= pch_phub_write_serial_rom(chip, 0x18, 0x19); + + retval |= pch_phub_write_serial_rom(chip, 0x23, 0xbc); + retval |= pch_phub_write_serial_rom(chip, 0x22, 0x10); + retval |= pch_phub_write_serial_rom(chip, 0x21, 0x01); + retval |= pch_phub_write_serial_rom(chip, 0x20, 0x3a); + + retval |= pch_phub_write_serial_rom(chip, 0x27, 0x01); + retval |= pch_phub_write_serial_rom(chip, 0x26, 0x00); + retval |= pch_phub_write_serial_rom(chip, 0x25, 0x00); + retval |= pch_phub_write_serial_rom(chip, 0x24, 0x00); + + return retval; +} + +/** + * pch_phub_read_gbe_mac_addr() - Read Gigabit Ethernet MAC address + * @offset_address: Gigabit Ethernet MAC address offset value. + * @data: Buffer of the Gigabit Ethernet MAC address value. + */ +static void pch_phub_read_gbe_mac_addr(struct pch_phub_reg *chip, u8 *data) +{ + int i; + for (i = 0; i < ETH_ALEN; i++) + pch_phub_read_serial_rom_val(chip, i, &data[i]); +} + +/** + * pch_phub_write_gbe_mac_addr() - Write MAC address + * @offset_address: Gigabit Ethernet MAC address offset value. + * @data: Gigabit Ethernet MAC address value. + */ +static int pch_phub_write_gbe_mac_addr(struct pch_phub_reg *chip, u8 *data) +{ + int retval; + int i; + + retval = pch_phub_gbe_serial_rom_conf(chip); + if (retval) + return retval; + + for (i = 0; i < ETH_ALEN; i++) { + retval = pch_phub_write_serial_rom_val(chip, i, data[i]); + if (retval) + return retval; + } + + return retval; +} + +static ssize_t pch_phub_bin_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t off, size_t count) +{ + unsigned int rom_signature; + unsigned char rom_length; + unsigned int tmp; + unsigned int addr_offset; + unsigned int orom_size; + int ret; + int err; + + struct pch_phub_reg *chip = + dev_get_drvdata(container_of(kobj, struct device, kobj)); + + ret = mutex_lock_interruptible(&pch_phub_mutex); + if (ret) { + err = -ERESTARTSYS; + goto return_err_nomutex; + } + + /* Get Rom signature */ + pch_phub_read_serial_rom(chip, 0x80, (unsigned char *)&rom_signature); + rom_signature &= 0xff; + pch_phub_read_serial_rom(chip, 0x81, (unsigned char *)&tmp); + rom_signature |= (tmp & 0xff) << 8; + if (rom_signature == 0xAA55) { + pch_phub_read_serial_rom(chip, 0x82, &rom_length); + orom_size = rom_length * 512; + if (orom_size < off) { + addr_offset = 0; + goto return_ok; + } + if (orom_size < count) { + addr_offset = 0; + goto return_ok; + } + + for (addr_offset = 0; addr_offset < count; addr_offset++) { + pch_phub_read_serial_rom(chip, 0x80 + addr_offset + off, + &buf[addr_offset]); + } + } else { + err = -ENODATA; + goto return_err; + } +return_ok: + mutex_unlock(&pch_phub_mutex); + return addr_offset; + +return_err: + mutex_unlock(&pch_phub_mutex); +return_err_nomutex: + return err; +} + +static ssize_t pch_phub_bin_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + int err; + unsigned int addr_offset; + int ret; + struct pch_phub_reg *chip = + dev_get_drvdata(container_of(kobj, struct device, kobj)); + + ret = mutex_lock_interruptible(&pch_phub_mutex); + if (ret) + return -ERESTARTSYS; + + if (off > PCH_PHUB_OROM_SIZE) { + addr_offset = 0; + goto return_ok; + } + if (count > PCH_PHUB_OROM_SIZE) { + addr_offset = 0; + goto return_ok; + } + + for (addr_offset = 0; addr_offset < count; addr_offset++) { + if (PCH_PHUB_OROM_SIZE < off + addr_offset) + goto return_ok; + + ret = pch_phub_write_serial_rom(chip, 0x80 + addr_offset + off, + buf[addr_offset]); + if (ret) { + err = ret; + goto return_err; + } + } + +return_ok: + mutex_unlock(&pch_phub_mutex); + return addr_offset; + +return_err: + mutex_unlock(&pch_phub_mutex); + return err; +} + +static ssize_t show_pch_mac(struct device *dev, struct device_attribute *attr, + char *buf) +{ + u8 mac[8]; + struct pch_phub_reg *chip = dev_get_drvdata(dev); + + pch_phub_read_gbe_mac_addr(chip, mac); + + return sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); +} + +static ssize_t store_pch_mac(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + u8 mac[6]; + struct pch_phub_reg *chip = dev_get_drvdata(dev); + + if (count != 18) + return -EINVAL; + + sscanf(buf, "%02x:%02x:%02x:%02x:%02x:%02x", + (u32 *)&mac[0], (u32 *)&mac[1], (u32 *)&mac[2], (u32 *)&mac[3], + (u32 *)&mac[4], (u32 *)&mac[5]); + + pch_phub_write_gbe_mac_addr(chip, mac); + + return count; +} + +static DEVICE_ATTR(pch_mac, S_IRUGO | S_IWUSR, show_pch_mac, store_pch_mac); + +static struct bin_attribute pch_bin_attr = { + .attr = { + .name = "pch_firmware", + .mode = S_IRUGO | S_IWUSR, + }, + .size = PCH_PHUB_OROM_SIZE + 1, + .read = pch_phub_bin_read, + .write = pch_phub_bin_write, +}; + +static int __devinit pch_phub_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + int retval; + + int ret; + ssize_t rom_size; + struct pch_phub_reg *chip; + + chip = kzalloc(sizeof(struct pch_phub_reg), GFP_KERNEL); + if (chip == NULL) + return -ENOMEM; + + ret = pci_enable_device(pdev); + if (ret) { + dev_err(&pdev->dev, + "%s : pci_enable_device FAILED(ret=%d)", __func__, ret); + goto err_pci_enable_dev; + } + dev_dbg(&pdev->dev, "%s : pci_enable_device returns %d\n", __func__, + ret); + + ret = pci_request_regions(pdev, KBUILD_MODNAME); + if (ret) { + dev_err(&pdev->dev, + "%s : pci_request_regions FAILED(ret=%d)", __func__, ret); + goto err_req_regions; + } + dev_dbg(&pdev->dev, "%s : " + "pci_request_regions returns %d\n", __func__, ret); + + chip->pch_phub_base_address = pci_iomap(pdev, 1, 0); + + + if (chip->pch_phub_base_address == 0) { + dev_err(&pdev->dev, "%s : pci_iomap FAILED", __func__); + ret = -ENOMEM; + goto err_pci_iomap; + } + dev_dbg(&pdev->dev, "%s : pci_iomap SUCCESS and value " + "in pch_phub_base_address variable is %p\n", __func__, + chip->pch_phub_base_address); + chip->pch_phub_extrom_base_address = pci_map_rom(pdev, &rom_size); + + if (chip->pch_phub_extrom_base_address == 0) { + dev_err(&pdev->dev, "%s : pci_map_rom FAILED", __func__); + ret = -ENOMEM; + goto err_pci_map; + } + dev_dbg(&pdev->dev, "%s : " + "pci_map_rom SUCCESS and value in " + "pch_phub_extrom_base_address variable is %p\n", __func__, + chip->pch_phub_extrom_base_address); + + pci_set_drvdata(pdev, chip); + + retval = sysfs_create_file(&pdev->dev.kobj, &dev_attr_pch_mac.attr); + if (retval) + goto err_sysfs_create; + + retval = sysfs_create_bin_file(&pdev->dev.kobj, &pch_bin_attr); + if (retval) + goto exit_bin_attr; + + pch_phub_read_modify_write_reg(chip, (unsigned int)CLKCFG_REG_OFFSET, + CLKCFG_CAN_50MHZ, CLKCFG_CANCLK_MASK); + + /* set the prefech value */ + iowrite32(0x000affaa, chip->pch_phub_base_address + 0x14); + /* set the interrupt delay value */ + iowrite32(0x25, chip->pch_phub_base_address + 0x44); + + return 0; +exit_bin_attr: + sysfs_remove_file(&pdev->dev.kobj, &dev_attr_pch_mac.attr); + +err_sysfs_create: + pci_unmap_rom(pdev, chip->pch_phub_extrom_base_address); +err_pci_map: + pci_iounmap(pdev, chip->pch_phub_base_address); +err_pci_iomap: + pci_release_regions(pdev); +err_req_regions: + pci_disable_device(pdev); +err_pci_enable_dev: + kfree(chip); + dev_err(&pdev->dev, "%s returns %d\n", __func__, ret); + return ret; +} + +static void __devexit pch_phub_remove(struct pci_dev *pdev) +{ + struct pch_phub_reg *chip = pci_get_drvdata(pdev); + + sysfs_remove_file(&pdev->dev.kobj, &dev_attr_pch_mac.attr); + sysfs_remove_bin_file(&pdev->dev.kobj, &pch_bin_attr); + pci_unmap_rom(pdev, chip->pch_phub_extrom_base_address); + pci_iounmap(pdev, chip->pch_phub_base_address); + pci_release_regions(pdev); + pci_disable_device(pdev); + kfree(chip); +} + +#ifdef CONFIG_PM + +static int pch_phub_suspend(struct pci_dev *pdev, pm_message_t state) +{ + int ret; + + pch_phub_save_reg_conf(pdev); + ret = pci_save_state(pdev); + if (ret) { + dev_err(&pdev->dev, + " %s -pci_save_state returns %d\n", __func__, ret); + return ret; + } + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_disable_device(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + return 0; +} + +static int pch_phub_resume(struct pci_dev *pdev) +{ + int ret; + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + ret = pci_enable_device(pdev); + if (ret) { + dev_err(&pdev->dev, + "%s-pci_enable_device failed(ret=%d) ", __func__, ret); + return ret; + } + + pci_enable_wake(pdev, PCI_D3hot, 0); + pch_phub_restore_reg_conf(pdev); + + return 0; +} +#else +#define pch_phub_suspend NULL +#define pch_phub_resume NULL +#endif /* CONFIG_PM */ + +static struct pci_device_id pch_phub_pcidev_id[] = { + {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PCH1_PHUB)}, + {0,} +}; + +static struct pci_driver pch_phub_driver = { + .name = "pch_phub", + .id_table = pch_phub_pcidev_id, + .probe = pch_phub_probe, + .remove = __devexit_p(pch_phub_remove), + .suspend = pch_phub_suspend, + .resume = pch_phub_resume +}; + +static int __init pch_phub_pci_init(void) +{ + return pci_register_driver(&pch_phub_driver); +} + +static void __exit pch_phub_pci_exit(void) +{ + pci_unregister_driver(&pch_phub_driver); +} + +module_init(pch_phub_pci_init); +module_exit(pch_phub_pci_exit); + +MODULE_DESCRIPTION("PCH Packet Hub PCI Driver"); +MODULE_LICENSE("GPL"); |