diff --git a/[refs] b/[refs] index 6b27071f97b9..5c4c7877000d 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: a6cc48eeea438b9d9e05943beebc31c52e76d32f +refs/heads/master: c6fa0b03cdf7d973988193c2b7d768f01e1dc2ae diff --git a/trunk/Documentation/driver-model/platform.txt b/trunk/Documentation/driver-model/platform.txt index 83009fdcbbc8..2a97320ee17f 100644 --- a/trunk/Documentation/driver-model/platform.txt +++ b/trunk/Documentation/driver-model/platform.txt @@ -122,15 +122,15 @@ None the less, there are some APIs to support such legacy drivers. Avoid using these calls except with such hotplug-deficient drivers. struct platform_device *platform_device_alloc( - const char *name, int id); + char *name, unsigned id); You can use platform_device_alloc() to dynamically allocate a device, which you will then initialize with resources and platform_device_register(). A better solution is usually: struct platform_device *platform_device_register_simple( - const char *name, int id, - struct resource *res, unsigned int nres); + char *name, unsigned id, + struct resource *res, unsigned nres); You can use platform_device_register_simple() as a one-step call to allocate and register a device. diff --git a/trunk/Documentation/ja_JP/stable_kernel_rules.txt b/trunk/Documentation/ja_JP/stable_kernel_rules.txt deleted file mode 100644 index 17d87519e468..000000000000 --- a/trunk/Documentation/ja_JP/stable_kernel_rules.txt +++ /dev/null @@ -1,79 +0,0 @@ -NOTE: -This is Japanese translated version of "Documentation/stable_kernel_rules.txt". -This one is maintained by Tsugikazu Shibata -and JF Project team . -If you find difference with original file or problem in translation, -please contact maintainer of this file or JF project. - -Please also note that purpose of this file is easier to read for non -English natives and do no intended to fork. So, if you have any -comment or update of this file, please try to update Original(English) -file at first. - -================================== -これは、 -linux-2.6.24/Documentation/stable_kernel_rules.txt -の和訳です。 - -翻訳団体: JF プロジェクト < http://www.linux.or.jp/JF/ > -翻訳日: 2007/12/30 -翻訳者: Tsugikazu Shibata -校正者: 武井伸光さん、 - かねこさん (Seiji Kaneko) - 小林 雅典さん (Masanori Kobayasi) - 野口さん (Kenji Noguchi) - 神宮信太郎さん -================================== - -ずっと知りたかった Linux 2.6 -stable リリースの全て - -"-stable" ツリーにどのような種類のパッチが受け入れられるか、どのような -ものが受け入れられないか、についての規則- - - - 明らかに正しく、テストされているものでなければならない。 - - 文脈(変更行の前後)を含めて 100 行より大きくてはいけない。 - - ただ一個のことだけを修正しているべき。 - - 皆を悩ませている本物のバグを修正しなければならない。("これはバグで - あるかもしれないが..." のようなものではない) - - ビルドエラー(CONFIG_BROKENになっているものを除く), oops, ハング、デー - タ破壊、現実のセキュリティ問題、その他 "ああ、これはダメだね"という - ようなものを修正しなければならない。短く言えば、重大な問題。 - - どのように競合状態が発生するかの説明も一緒に書かれていない限り、 - "理論的には競合状態になる"ようなものは不可。 - - いかなる些細な修正も含めることはできない。(スペルの修正、空白のクリー - ンアップなど) - - 対応するサブシステムメンテナが受け入れたものでなければならない。 - - Documentation/SubmittingPatches の規則に従ったものでなければならない。 - --stable ツリーにパッチを送付する手続き- - - - 上記の規則に従っているかを確認した後に、stable@kernel.org にパッチ - を送る。 - - 送信者はパッチがキューに受け付けられた際には ACK を、却下された場合 - には NAK を受け取る。この反応は開発者たちのスケジュールによって、数 - 日かかる場合がある。 - - もし受け取られたら、パッチは他の開発者たちのレビューのために - -stable キューに追加される。 - - セキュリティパッチはこのエイリアス (stable@kernel.org) に送られるべ - きではなく、代わりに security@kernel.org のアドレスに送られる。 - -レビューサイクル- - - - -stable メンテナがレビューサイクルを決めるとき、パッチはレビュー委 - 員会とパッチが影響する領域のメンテナ(提供者がその領域のメンテナで無 - い限り)に送られ、linux-kernel メーリングリストにCCされる。 - - レビュー委員会は 48時間の間に ACK か NAK を出す。 - - もしパッチが委員会のメンバから却下れるか、メンテナ達やメンバが気付 - かなかった問題が持ちあがり、linux-kernel メンバがパッチに異議を唱え - た場合には、パッチはキューから削除される。 - - レビューサイクルの最後に、ACK を受けたパッチは最新の -stable リリー - スに追加され、その後に新しい -stable リリースが行われる。 - - セキュリティパッチは、通常のレビューサイクルを通らず、セキュリティ - カーネルチームから直接 -stable ツリーに受け付けられる。 - この手続きの詳細については kernel security チームに問い合わせること。 - -レビュー委員会- - - - この委員会は、このタスクについて活動する多くのボランティアと、少数の - 非ボランティアのカーネル開発者達で構成されている。 - diff --git a/trunk/drivers/base/core.c b/trunk/drivers/base/core.c index 9c0070b5bd3e..b1727876182c 100644 --- a/trunk/drivers/base/core.c +++ b/trunk/drivers/base/core.c @@ -423,8 +423,10 @@ struct kset *devices_kset; int device_create_file(struct device *dev, struct device_attribute *attr) { int error = 0; - if (dev) + if (get_device(dev)) { error = sysfs_create_file(&dev->kobj, &attr->attr); + put_device(dev); + } return error; } @@ -435,8 +437,10 @@ int device_create_file(struct device *dev, struct device_attribute *attr) */ void device_remove_file(struct device *dev, struct device_attribute *attr) { - if (dev) + if (get_device(dev)) { sysfs_remove_file(&dev->kobj, &attr->attr); + put_device(dev); + } } /** @@ -1140,11 +1144,25 @@ struct device *device_create(struct class *class, struct device *parent, } EXPORT_SYMBOL_GPL(device_create); -static int __match_devt(struct device *dev, void *data) +/** + * find_device - finds a device that was created with device_create() + * @class: pointer to the struct class that this device was registered with + * @devt: the dev_t of the device that was previously registered + */ +static struct device *find_device(struct class *class, dev_t devt) { - dev_t *devt = data; + struct device *dev = NULL; + struct device *dev_tmp; - return dev->devt == *devt; + down(&class->sem); + list_for_each_entry(dev_tmp, &class->devices, node) { + if (dev_tmp->devt == devt) { + dev = dev_tmp; + break; + } + } + up(&class->sem); + return dev; } /** @@ -1159,11 +1177,9 @@ void device_destroy(struct class *class, dev_t devt) { struct device *dev; - dev = class_find_device(class, &devt, __match_devt); - if (dev) { - put_device(dev); + dev = find_device(class, devt); + if (dev) device_unregister(dev); - } } EXPORT_SYMBOL_GPL(device_destroy); @@ -1187,11 +1203,9 @@ void destroy_suspended_device(struct class *class, dev_t devt) { struct device *dev; - dev = class_find_device(class, &devt, __match_devt); - if (dev) { + dev = find_device(class, devt); + if (dev) device_pm_schedule_removal(dev); - put_device(dev); - } } EXPORT_SYMBOL_GPL(destroy_suspended_device); #endif /* CONFIG_PM_SLEEP */ diff --git a/trunk/drivers/base/driver.c b/trunk/drivers/base/driver.c index ba75184c653c..a35f04121a00 100644 --- a/trunk/drivers/base/driver.c +++ b/trunk/drivers/base/driver.c @@ -97,9 +97,10 @@ int driver_create_file(struct device_driver *drv, struct driver_attribute *attr) { int error; - if (drv) + if (get_driver(drv)) { error = sysfs_create_file(&drv->p->kobj, &attr->attr); - else + put_driver(drv); + } else error = -EINVAL; return error; } @@ -113,8 +114,10 @@ EXPORT_SYMBOL_GPL(driver_create_file); void driver_remove_file(struct device_driver *drv, struct driver_attribute *attr) { - if (drv) + if (get_driver(drv)) { sysfs_remove_file(&drv->p->kobj, &attr->attr); + put_driver(drv); + } } EXPORT_SYMBOL_GPL(driver_remove_file); diff --git a/trunk/drivers/base/power/main.c b/trunk/drivers/base/power/main.c index bdc03f7e8424..200ed5fafd50 100644 --- a/trunk/drivers/base/power/main.c +++ b/trunk/drivers/base/power/main.c @@ -129,7 +129,6 @@ void device_pm_schedule_removal(struct device *dev) list_move_tail(&dev->power.entry, &dpm_destroy); mutex_unlock(&dpm_list_mtx); } -EXPORT_SYMBOL_GPL(device_pm_schedule_removal); /** * pm_sleep_lock - mutual exclusion for registration and suspend diff --git a/trunk/drivers/base/power/power.h b/trunk/drivers/base/power/power.h index e32d3bdb92c1..6f0dfca8ebdd 100644 --- a/trunk/drivers/base/power/power.h +++ b/trunk/drivers/base/power/power.h @@ -13,6 +13,7 @@ static inline struct device *to_device(struct list_head *entry) extern void device_pm_add(struct device *); extern void device_pm_remove(struct device *); +extern void device_pm_schedule_removal(struct device *); extern int pm_sleep_lock(void); extern void pm_sleep_unlock(void); diff --git a/trunk/drivers/char/nozomi.c b/trunk/drivers/char/nozomi.c index dfaab2322de3..6076e662886a 100644 --- a/trunk/drivers/char/nozomi.c +++ b/trunk/drivers/char/nozomi.c @@ -2,7 +2,7 @@ * nozomi.c -- HSDPA driver Broadband Wireless Data Card - Globe Trotter * * Written by: Ulf Jakobsson, - * Jan Åkerfeldt, + * Jan �erfeldt, * Stefan Thomasson, * * Maintained by: Paul Hardwick (p.hardwick@option.com) @@ -38,6 +38,60 @@ * -------------------------------------------------------------------------- */ +/* + * CHANGELOG + * Version 2.1d + * 11-November-2007 Jiri Slaby, Frank Seidel + * - Big rework of multicard support by Jiri + * - Major cleanups (semaphore to mutex, endianess, no major reservation) + * - Optimizations + * + * Version 2.1c + * 30-October-2007 Frank Seidel + * - Completed multicard support + * - Minor cleanups + * + * Version 2.1b + * 07-August-2007 Frank Seidel + * - Minor cleanups + * - theoretical multicard support + * + * Version 2.1 + * 03-July-2006 Paul Hardwick + * + * - Stability Improvements. Incorporated spinlock wraps patch. + * - Updated for newer 2.6.14+ kernels (tty_buffer_request_room) + * - using __devexit macro for tty + * + * + * Version 2.0 + * 08-feb-2006 15:34:10:Ulf + * + * -Fixed issue when not waking up line disipine layer, could probably result + * in better uplink performance for 2.4. + * + * -Fixed issue with big endian during initalization, now proper toggle flags + * are handled between preloader and maincode. + * + * -Fixed flow control issue. + * + * -Added support for setting DTR. + * + * -For 2.4 kernels, removing temporary buffer that's not needed. + * + * -Reading CTS only for modem port (only port that supports it). + * + * -Return 0 in write_room instead of netative value, it's not handled in + * upper layer. + * + * -------------------------------------------------------------------------- + * Version 1.0 + * + * First version of driver, only tested with card of type F32_2. + * Works fine with 2.4 and 2.6 kernels. + * Driver also support big endian architecture. + */ + /* Enable this to have a lot of debug printouts */ #define DEBUG @@ -89,9 +143,8 @@ do { \ /* Do we need this settable at runtime? */ static int debug = NOZOMI_DEBUG_LEVEL; -#define D(lvl, args...) do \ - {if (lvl & debug) NFO(KERN_DEBUG, ##args); } \ - while (0) +#define D(lvl, args...) do {if (lvl & debug) NFO(KERN_DEBUG, ##args); } \ + while (0) #define D_(lvl, args...) D(lvl, ##args) /* These printouts are always printed */ @@ -220,13 +273,13 @@ enum port_type { /* Big endian */ struct toggles { - unsigned int enabled:5; /* + unsigned enabled:5; /* * Toggle fields are valid if enabled is 0, * else A-channels must always be used. */ - unsigned int diag_dl:1; - unsigned int mdm_dl:1; - unsigned int mdm_ul:1; + unsigned diag_dl:1; + unsigned mdm_dl:1; + unsigned mdm_ul:1; } __attribute__ ((packed)); /* Configuration table to read at startup of card */ @@ -267,19 +320,19 @@ struct config_table { /* This stores all control downlink flags */ struct ctrl_dl { u8 port; - unsigned int reserved:4; - unsigned int CTS:1; - unsigned int RI:1; - unsigned int DCD:1; - unsigned int DSR:1; + unsigned reserved:4; + unsigned CTS:1; + unsigned RI:1; + unsigned DCD:1; + unsigned DSR:1; } __attribute__ ((packed)); /* This stores all control uplink flags */ struct ctrl_ul { u8 port; - unsigned int reserved:6; - unsigned int RTS:1; - unsigned int DTR:1; + unsigned reserved:6; + unsigned RTS:1; + unsigned DTR:1; } __attribute__ ((packed)); #else @@ -287,10 +340,10 @@ struct ctrl_ul { /* This represents the toggle information */ struct toggles { - unsigned int mdm_ul:1; - unsigned int mdm_dl:1; - unsigned int diag_dl:1; - unsigned int enabled:5; /* + unsigned mdm_ul:1; + unsigned mdm_dl:1; + unsigned diag_dl:1; + unsigned enabled:5; /* * Toggle fields are valid if enabled is 0, * else A-channels must always be used. */ @@ -326,19 +379,19 @@ struct config_table { /* This stores all control downlink flags */ struct ctrl_dl { - unsigned int DSR:1; - unsigned int DCD:1; - unsigned int RI:1; - unsigned int CTS:1; - unsigned int reserverd:4; + unsigned DSR:1; + unsigned DCD:1; + unsigned RI:1; + unsigned CTS:1; + unsigned reserverd:4; u8 port; } __attribute__ ((packed)); /* This stores all control uplink flags */ struct ctrl_ul { - unsigned int DTR:1; - unsigned int RTS:1; - unsigned int reserved:6; + unsigned DTR:1; + unsigned RTS:1; + unsigned reserved:6; u8 port; } __attribute__ ((packed)); #endif @@ -395,7 +448,7 @@ struct buffer { } __attribute__ ((packed)); /* Global variables */ -static const struct pci_device_id nozomi_pci_tbl[] __devinitconst = { +static struct pci_device_id nozomi_pci_tbl[] = { {PCI_DEVICE(VENDOR1, DEVICE1)}, {}, }; @@ -471,12 +524,12 @@ static void read_mem32(u32 *buf, const void __iomem *mem_addr_start, * -Optimize * -Rewrite cleaner */ -static u32 write_mem32(void __iomem *mem_addr_start, const u32 *buf, +static u32 write_mem32(void __iomem *mem_addr_start, u32 *buf, u32 size_bytes) { u32 i = 0; u32 *ptr = (__force u32 *) mem_addr_start; - const u16 *buf16; + u16 *buf16; if (unlikely(!ptr || !buf)) return 0; @@ -484,7 +537,7 @@ static u32 write_mem32(void __iomem *mem_addr_start, const u32 *buf, /* shortcut for extremely often used cases */ switch (size_bytes) { case 2: /* 2 bytes */ - buf16 = (const u16 *)buf; + buf16 = (u16 *) buf; writew(__cpu_to_le16(*buf16), (void __iomem *)ptr); return 2; break; @@ -501,7 +554,7 @@ static u32 write_mem32(void __iomem *mem_addr_start, const u32 *buf, while (i < size_bytes) { if (size_bytes - i == 2) { /* 2 bytes */ - buf16 = (const u16 *)buf; + buf16 = (u16 *) buf; writew(__cpu_to_le16(*buf16), (void __iomem *)ptr); i += 2; } else { @@ -641,7 +694,7 @@ static void dump_table(const struct nozomi *dc) dc->config_table.ul_ctrl_len); } #else -static inline void dump_table(const struct nozomi *dc) { } +static __inline__ void dump_table(const struct nozomi *dc) { } #endif /* @@ -723,7 +776,8 @@ static int nozomi_read_config_table(struct nozomi *dc) /* Enable uplink interrupts */ static void enable_transmit_ul(enum port_type port, struct nozomi *dc) { - static const u16 mask[] = {MDM_UL, DIAG_UL, APP1_UL, APP2_UL, CTRL_UL}; + u16 mask[NOZOMI_MAX_PORTS] = \ + {MDM_UL, DIAG_UL, APP1_UL, APP2_UL, CTRL_UL}; if (port < NOZOMI_MAX_PORTS) { dc->last_ier |= mask[port]; @@ -736,8 +790,8 @@ static void enable_transmit_ul(enum port_type port, struct nozomi *dc) /* Disable uplink interrupts */ static void disable_transmit_ul(enum port_type port, struct nozomi *dc) { - static const u16 mask[] = - {~MDM_UL, ~DIAG_UL, ~APP1_UL, ~APP2_UL, ~CTRL_UL}; + u16 mask[NOZOMI_MAX_PORTS] = \ + {~MDM_UL, ~DIAG_UL, ~APP1_UL, ~APP2_UL, ~CTRL_UL}; if (port < NOZOMI_MAX_PORTS) { dc->last_ier &= mask[port]; @@ -750,7 +804,8 @@ static void disable_transmit_ul(enum port_type port, struct nozomi *dc) /* Enable downlink interrupts */ static void enable_transmit_dl(enum port_type port, struct nozomi *dc) { - static const u16 mask[] = {MDM_DL, DIAG_DL, APP1_DL, APP2_DL, CTRL_DL}; + u16 mask[NOZOMI_MAX_PORTS] = \ + {MDM_DL, DIAG_DL, APP1_DL, APP2_DL, CTRL_DL}; if (port < NOZOMI_MAX_PORTS) { dc->last_ier |= mask[port]; @@ -763,8 +818,8 @@ static void enable_transmit_dl(enum port_type port, struct nozomi *dc) /* Disable downlink interrupts */ static void disable_transmit_dl(enum port_type port, struct nozomi *dc) { - static const u16 mask[] = - {~MDM_DL, ~DIAG_DL, ~APP1_DL, ~APP2_DL, ~CTRL_DL}; + u16 mask[NOZOMI_MAX_PORTS] = \ + {~MDM_DL, ~DIAG_DL, ~APP1_DL, ~APP2_DL, ~CTRL_DL}; if (port < NOZOMI_MAX_PORTS) { dc->last_ier &= mask[port]; @@ -778,13 +833,13 @@ static void disable_transmit_dl(enum port_type port, struct nozomi *dc) * Return 1 - send buffer to card and ack. * Return 0 - don't ack, don't send buffer to card. */ -static int send_data(enum port_type index, const struct nozomi *dc) +static int send_data(enum port_type index, struct nozomi *dc) { u32 size = 0; - const struct port *port = &dc->port[index]; - const u8 toggle = port->toggle_ul; + struct port *port = &dc->port[index]; + u8 toggle = port->toggle_ul; void __iomem *addr = port->ul_addr[toggle]; - const u32 ul_size = port->ul_size[toggle]; + u32 ul_size = port->ul_size[toggle]; struct tty_struct *tty = port->tty; /* Get data from tty and place in buf for now */ @@ -1047,7 +1102,7 @@ static int send_flow_control(struct nozomi *dc) } /* - * Handle downlink data, ports that are handled are modem and diagnostics + * Handle donlink data, ports that are handled are modem and diagnostics * Return 1 - ok * Return 0 - toggle fields are out of sync */ @@ -1304,20 +1359,20 @@ static void nozomi_setup_private_data(struct nozomi *dc) static ssize_t card_type_show(struct device *dev, struct device_attribute *attr, char *buf) { - const struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev)); + struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev)); return sprintf(buf, "%d\n", dc->card_type); } -static DEVICE_ATTR(card_type, S_IRUGO, card_type_show, NULL); +static DEVICE_ATTR(card_type, 0444, card_type_show, NULL); static ssize_t open_ttys_show(struct device *dev, struct device_attribute *attr, char *buf) { - const struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev)); + struct nozomi *dc = pci_get_drvdata(to_pci_dev(dev)); return sprintf(buf, "%u\n", dc->open_ttys); } -static DEVICE_ATTR(open_ttys, S_IRUGO, open_ttys_show, NULL); +static DEVICE_ATTR(open_ttys, 0444, open_ttys_show, NULL); static void make_sysfs_files(struct nozomi *dc) { @@ -1680,7 +1735,7 @@ static int ntty_write_room(struct tty_struct *tty) { struct port *port = tty->driver_data; int room = 0; - const struct nozomi *dc = get_dc_by_tty(tty); + struct nozomi *dc = get_dc_by_tty(tty); if (!dc || !port) return 0; @@ -1700,9 +1755,9 @@ static int ntty_write_room(struct tty_struct *tty) /* Gets io control parameters */ static int ntty_tiocmget(struct tty_struct *tty, struct file *file) { - const struct port *port = tty->driver_data; - const struct ctrl_dl *ctrl_dl = &port->ctrl_dl; - const struct ctrl_ul *ctrl_ul = &port->ctrl_ul; + struct port *port = tty->driver_data; + struct ctrl_dl *ctrl_dl = &port->ctrl_dl; + struct ctrl_ul *ctrl_ul = &port->ctrl_ul; return (ctrl_ul->RTS ? TIOCM_RTS : 0) | (ctrl_ul->DTR ? TIOCM_DTR : 0) | @@ -1732,7 +1787,7 @@ static int ntty_tiocmset(struct tty_struct *tty, struct file *file, static int ntty_cflags_changed(struct port *port, unsigned long flags, struct async_icount *cprev) { - const struct async_icount cnow = port->tty_icount; + struct async_icount cnow = port->tty_icount; int ret; ret = ((flags & TIOCM_RNG) && (cnow.rng != cprev->rng)) || @@ -1747,7 +1802,7 @@ static int ntty_cflags_changed(struct port *port, unsigned long flags, static int ntty_ioctl_tiocgicount(struct port *port, void __user *argp) { - const struct async_icount cnow = port->tty_icount; + struct async_icount cnow = port->tty_icount; struct serial_icounter_struct icount; icount.cts = cnow.cts; @@ -1827,10 +1882,7 @@ static void ntty_throttle(struct tty_struct *tty) /* just to discard single character writes */ static void ntty_put_char(struct tty_struct *tty, unsigned char c) { - /* - * card does not react correct when we write single chars - * to the card, so we discard them - */ + /* FIXME !!! */ DBG2("PUT CHAR Function: %c", c); } @@ -1858,7 +1910,7 @@ static s32 ntty_chars_in_buffer(struct tty_struct *tty) return rval; } -static const struct tty_operations tty_ops = { +static struct tty_operations tty_ops = { .ioctl = ntty_ioctl, .open = ntty_open, .close = ntty_close, diff --git a/trunk/drivers/net/ehea/ehea.h b/trunk/drivers/net/ehea/ehea.h index 5f82a4647eee..88fb53eba715 100644 --- a/trunk/drivers/net/ehea/ehea.h +++ b/trunk/drivers/net/ehea/ehea.h @@ -458,4 +458,7 @@ void ehea_set_ethtool_ops(struct net_device *netdev); int ehea_sense_port_attr(struct ehea_port *port); int ehea_set_portspeed(struct ehea_port *port, u32 port_speed); +extern u64 ehea_driver_flags; +extern struct work_struct ehea_rereg_mr_task; + #endif /* __EHEA_H__ */ diff --git a/trunk/drivers/net/ehea/ehea_hw.h b/trunk/drivers/net/ehea/ehea_hw.h index 1af7ca499ec5..567981b4b2cc 100644 --- a/trunk/drivers/net/ehea/ehea_hw.h +++ b/trunk/drivers/net/ehea/ehea_hw.h @@ -29,10 +29,10 @@ #ifndef __EHEA_HW_H__ #define __EHEA_HW_H__ -#define QPX_SQA_VALUE EHEA_BMASK_IBM(48,63) -#define QPX_RQ1A_VALUE EHEA_BMASK_IBM(48,63) -#define QPX_RQ2A_VALUE EHEA_BMASK_IBM(48,63) -#define QPX_RQ3A_VALUE EHEA_BMASK_IBM(48,63) +#define QPX_SQA_VALUE EHEA_BMASK_IBM(48, 63) +#define QPX_RQ1A_VALUE EHEA_BMASK_IBM(48, 63) +#define QPX_RQ2A_VALUE EHEA_BMASK_IBM(48, 63) +#define QPX_RQ3A_VALUE EHEA_BMASK_IBM(48, 63) #define QPTEMM_OFFSET(x) offsetof(struct ehea_qptemm, x) diff --git a/trunk/drivers/pci/Makefile b/trunk/drivers/pci/Makefile index 9f04d17576d6..f697f3d728eb 100644 --- a/trunk/drivers/pci/Makefile +++ b/trunk/drivers/pci/Makefile @@ -13,9 +13,6 @@ obj-$(CONFIG_HOTPLUG) += hotplug.o # Build the PCI Hotplug drivers if we were asked to obj-$(CONFIG_HOTPLUG_PCI) += hotplug/ -ifdef CONFIG_HOTPLUG_PCI -obj-y += hotplug-pci.o -endif # Build the PCI MSI interrupt support obj-$(CONFIG_PCI_MSI) += msi.o diff --git a/trunk/drivers/pci/hotplug-pci.c b/trunk/drivers/pci/hotplug-pci.c deleted file mode 100644 index a590ef682153..000000000000 --- a/trunk/drivers/pci/hotplug-pci.c +++ /dev/null @@ -1,20 +0,0 @@ -/* Core PCI functionality used only by PCI hotplug */ - -#include -#include "pci.h" - - -unsigned int pci_do_scan_bus(struct pci_bus *bus) -{ - unsigned int max; - - max = pci_scan_child_bus(bus); - - /* - * Make the discovered devices available. - */ - pci_bus_add_devices(bus); - - return max; -} -EXPORT_SYMBOL(pci_do_scan_bus); diff --git a/trunk/drivers/pci/pci-sysfs.c b/trunk/drivers/pci/pci-sysfs.c index 8dcf1458aa2f..abf4203304e4 100644 --- a/trunk/drivers/pci/pci-sysfs.c +++ b/trunk/drivers/pci/pci-sysfs.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "pci.h" static int sysfs_initialized; /* = 0 */ @@ -650,6 +651,8 @@ int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev) if (pcibios_add_platform_entries(pdev)) goto err_rom_file; + pcie_aspm_create_sysfs_dev_files(pdev); + return 0; err_rom_file: @@ -679,6 +682,8 @@ void pci_remove_sysfs_dev_files(struct pci_dev *pdev) if (!sysfs_initialized) return; + pcie_aspm_remove_sysfs_dev_files(pdev); + if (pdev->cfg_size < 4096) sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr); else diff --git a/trunk/drivers/pci/pci.c b/trunk/drivers/pci/pci.c index 04aac7782468..b3e9294e4a0e 100644 --- a/trunk/drivers/pci/pci.c +++ b/trunk/drivers/pci/pci.c @@ -18,6 +18,7 @@ #include #include #include +#include #include /* isa_dma_bridge_buggy */ #include "pci.h" @@ -519,6 +520,9 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state) if (need_restore) pci_restore_bars(dev); + if (dev->bus->self) + pcie_aspm_pm_state_change(dev->bus->self); + return 0; } diff --git a/trunk/drivers/pci/pcie/Kconfig b/trunk/drivers/pci/pcie/Kconfig index 287a9311716c..60104cf98796 100644 --- a/trunk/drivers/pci/pcie/Kconfig +++ b/trunk/drivers/pci/pcie/Kconfig @@ -26,3 +26,23 @@ config HOTPLUG_PCI_PCIE When in doubt, say N. source "drivers/pci/pcie/aer/Kconfig" + +# +# PCI Express ASPM +# +config PCIEASPM + bool "PCI Express ASPM support(Experimental)" + depends on PCI && EXPERIMENTAL + default y + help + This enables PCI Express ASPM (Active State Power Management) and + Clock Power Management. ASPM supports state L0/L0s/L1. + + When in doubt, say N. +config PCIEASPM_DEBUG + bool "Debug PCI Express ASPM" + depends on PCIEASPM + default n + help + This enables PCI Express ASPM debug support. It will add per-device + interface to control ASPM. diff --git a/trunk/drivers/pci/pcie/Makefile b/trunk/drivers/pci/pcie/Makefile index e00fb99acf44..11f6bb1eae24 100644 --- a/trunk/drivers/pci/pcie/Makefile +++ b/trunk/drivers/pci/pcie/Makefile @@ -2,6 +2,9 @@ # Makefile for PCI-Express PORT Driver # +# Build PCI Express ASPM if needed +obj-$(CONFIG_PCIEASPM) += aspm.o + pcieportdrv-y := portdrv_core.o portdrv_pci.o portdrv_bus.o obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o diff --git a/trunk/drivers/pci/pcie/aspm.c b/trunk/drivers/pci/pcie/aspm.c new file mode 100644 index 000000000000..1a5adeb10c95 --- /dev/null +++ b/trunk/drivers/pci/pcie/aspm.c @@ -0,0 +1,802 @@ +/* + * File: drivers/pci/pcie/aspm.c + * Enabling PCIE link L0s/L1 state and Clock Power Management + * + * Copyright (C) 2007 Intel + * Copyright (C) Zhang Yanmin (yanmin.zhang@intel.com) + * Copyright (C) Shaohua Li (shaohua.li@intel.com) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../pci.h" + +#ifdef MODULE_PARAM_PREFIX +#undef MODULE_PARAM_PREFIX +#endif +#define MODULE_PARAM_PREFIX "pcie_aspm." + +struct endpoint_state { + unsigned int l0s_acceptable_latency; + unsigned int l1_acceptable_latency; +}; + +struct pcie_link_state { + struct list_head sibiling; + struct pci_dev *pdev; + + /* ASPM state */ + unsigned int support_state; + unsigned int enabled_state; + unsigned int bios_aspm_state; + /* upstream component */ + unsigned int l0s_upper_latency; + unsigned int l1_upper_latency; + /* downstream component */ + unsigned int l0s_down_latency; + unsigned int l1_down_latency; + /* Clock PM state*/ + unsigned int clk_pm_capable; + unsigned int clk_pm_enabled; + unsigned int bios_clk_state; + + /* + * A pcie downstream port only has one slot under it, so at most there + * are 8 functions + */ + struct endpoint_state endpoints[8]; +}; + +static int aspm_disabled; +static DEFINE_MUTEX(aspm_lock); +static LIST_HEAD(link_list); + +#define POLICY_DEFAULT 0 /* BIOS default setting */ +#define POLICY_PERFORMANCE 1 /* high performance */ +#define POLICY_POWERSAVE 2 /* high power saving */ +static int aspm_policy; +static const char *policy_str[] = { + [POLICY_DEFAULT] = "default", + [POLICY_PERFORMANCE] = "performance", + [POLICY_POWERSAVE] = "powersave" +}; + +static int policy_to_aspm_state(struct pci_dev *pdev) +{ + struct pcie_link_state *link_state = pdev->link_state; + + switch (aspm_policy) { + case POLICY_PERFORMANCE: + /* Disable ASPM and Clock PM */ + return 0; + case POLICY_POWERSAVE: + /* Enable ASPM L0s/L1 */ + return PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1; + case POLICY_DEFAULT: + return link_state->bios_aspm_state; + } + return 0; +} + +static int policy_to_clkpm_state(struct pci_dev *pdev) +{ + struct pcie_link_state *link_state = pdev->link_state; + + switch (aspm_policy) { + case POLICY_PERFORMANCE: + /* Disable ASPM and Clock PM */ + return 0; + case POLICY_POWERSAVE: + /* Disable Clock PM */ + return 1; + case POLICY_DEFAULT: + return link_state->bios_clk_state; + } + return 0; +} + +static void pcie_set_clock_pm(struct pci_dev *pdev, int enable) +{ + struct pci_dev *child_dev; + int pos; + u16 reg16; + struct pcie_link_state *link_state = pdev->link_state; + + list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { + pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); + if (!pos) + return; + pci_read_config_word(child_dev, pos + PCI_EXP_LNKCTL, ®16); + if (enable) + reg16 |= PCI_EXP_LNKCTL_CLKREQ_EN; + else + reg16 &= ~PCI_EXP_LNKCTL_CLKREQ_EN; + pci_write_config_word(child_dev, pos + PCI_EXP_LNKCTL, reg16); + } + link_state->clk_pm_enabled = !!enable; +} + +static void pcie_check_clock_pm(struct pci_dev *pdev) +{ + int pos; + u32 reg32; + u16 reg16; + int capable = 1, enabled = 1; + struct pci_dev *child_dev; + struct pcie_link_state *link_state = pdev->link_state; + + /* All functions should have the same cap and state, take the worst */ + list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { + pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); + if (!pos) + return; + pci_read_config_dword(child_dev, pos + PCI_EXP_LNKCAP, ®32); + if (!(reg32 & PCI_EXP_LNKCAP_CLKPM)) { + capable = 0; + enabled = 0; + break; + } + pci_read_config_word(child_dev, pos + PCI_EXP_LNKCTL, ®16); + if (!(reg16 & PCI_EXP_LNKCTL_CLKREQ_EN)) + enabled = 0; + } + link_state->clk_pm_capable = capable; + link_state->clk_pm_enabled = enabled; + link_state->bios_clk_state = enabled; + pcie_set_clock_pm(pdev, policy_to_clkpm_state(pdev)); +} + +/* + * pcie_aspm_configure_common_clock: check if the 2 ends of a link + * could use common clock. If they are, configure them to use the + * common clock. That will reduce the ASPM state exit latency. + */ +static void pcie_aspm_configure_common_clock(struct pci_dev *pdev) +{ + int pos, child_pos; + u16 reg16 = 0; + struct pci_dev *child_dev; + int same_clock = 1; + + /* + * all functions of a slot should have the same Slot Clock + * Configuration, so just check one function + * */ + child_dev = list_entry(pdev->subordinate->devices.next, struct pci_dev, + bus_list); + BUG_ON(!child_dev->is_pcie); + + /* Check downstream component if bit Slot Clock Configuration is 1 */ + child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); + pci_read_config_word(child_dev, child_pos + PCI_EXP_LNKSTA, ®16); + if (!(reg16 & PCI_EXP_LNKSTA_SLC)) + same_clock = 0; + + /* Check upstream component if bit Slot Clock Configuration is 1 */ + pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); + pci_read_config_word(pdev, pos + PCI_EXP_LNKSTA, ®16); + if (!(reg16 & PCI_EXP_LNKSTA_SLC)) + same_clock = 0; + + /* Configure downstream component, all functions */ + list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { + child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); + pci_read_config_word(child_dev, child_pos + PCI_EXP_LNKCTL, + ®16); + if (same_clock) + reg16 |= PCI_EXP_LNKCTL_CCC; + else + reg16 &= ~PCI_EXP_LNKCTL_CCC; + pci_write_config_word(child_dev, child_pos + PCI_EXP_LNKCTL, + reg16); + } + + /* Configure upstream component */ + pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16); + if (same_clock) + reg16 |= PCI_EXP_LNKCTL_CCC; + else + reg16 &= ~PCI_EXP_LNKCTL_CCC; + pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16); + + /* retrain link */ + reg16 |= PCI_EXP_LNKCTL_RL; + pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16); + + /* Wait for link training end */ + while (1) { + pci_read_config_word(pdev, pos + PCI_EXP_LNKSTA, ®16); + if (!(reg16 & PCI_EXP_LNKSTA_LT)) + break; + cpu_relax(); + } +} + +/* + * calc_L0S_latency: Convert L0s latency encoding to ns + */ +static unsigned int calc_L0S_latency(unsigned int latency_encoding, int ac) +{ + unsigned int ns = 64; + + if (latency_encoding == 0x7) { + if (ac) + ns = -1U; + else + ns = 5*1000; /* > 4us */ + } else + ns *= (1 << latency_encoding); + return ns; +} + +/* + * calc_L1_latency: Convert L1 latency encoding to ns + */ +static unsigned int calc_L1_latency(unsigned int latency_encoding, int ac) +{ + unsigned int ns = 1000; + + if (latency_encoding == 0x7) { + if (ac) + ns = -1U; + else + ns = 65*1000; /* > 64us */ + } else + ns *= (1 << latency_encoding); + return ns; +} + +static void pcie_aspm_get_cap_device(struct pci_dev *pdev, u32 *state, + unsigned int *l0s, unsigned int *l1, unsigned int *enabled) +{ + int pos; + u16 reg16; + u32 reg32; + unsigned int latency; + + pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); + pci_read_config_dword(pdev, pos + PCI_EXP_LNKCAP, ®32); + *state = (reg32 & PCI_EXP_LNKCAP_ASPMS) >> 10; + if (*state != PCIE_LINK_STATE_L0S && + *state != (PCIE_LINK_STATE_L1|PCIE_LINK_STATE_L0S)) + * state = 0; + if (*state == 0) + return; + + latency = (reg32 & PCI_EXP_LNKCAP_L0SEL) >> 12; + *l0s = calc_L0S_latency(latency, 0); + if (*state & PCIE_LINK_STATE_L1) { + latency = (reg32 & PCI_EXP_LNKCAP_L1EL) >> 15; + *l1 = calc_L1_latency(latency, 0); + } + pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16); + *enabled = reg16 & (PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1); +} + +static void pcie_aspm_cap_init(struct pci_dev *pdev) +{ + struct pci_dev *child_dev; + u32 state, tmp; + struct pcie_link_state *link_state = pdev->link_state; + + /* upstream component states */ + pcie_aspm_get_cap_device(pdev, &link_state->support_state, + &link_state->l0s_upper_latency, + &link_state->l1_upper_latency, + &link_state->enabled_state); + /* downstream component states, all functions have the same setting */ + child_dev = list_entry(pdev->subordinate->devices.next, struct pci_dev, + bus_list); + pcie_aspm_get_cap_device(child_dev, &state, + &link_state->l0s_down_latency, + &link_state->l1_down_latency, + &tmp); + link_state->support_state &= state; + if (!link_state->support_state) + return; + link_state->enabled_state &= link_state->support_state; + link_state->bios_aspm_state = link_state->enabled_state; + + /* ENDPOINT states*/ + list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { + int pos; + u32 reg32; + unsigned int latency; + struct endpoint_state *ep_state = + &link_state->endpoints[PCI_FUNC(child_dev->devfn)]; + + if (child_dev->pcie_type != PCI_EXP_TYPE_ENDPOINT && + child_dev->pcie_type != PCI_EXP_TYPE_LEG_END) + continue; + + pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP); + pci_read_config_dword(child_dev, pos + PCI_EXP_DEVCAP, ®32); + latency = (reg32 & PCI_EXP_DEVCAP_L0S) >> 6; + latency = calc_L0S_latency(latency, 1); + ep_state->l0s_acceptable_latency = latency; + if (link_state->support_state & PCIE_LINK_STATE_L1) { + latency = (reg32 & PCI_EXP_DEVCAP_L1) >> 9; + latency = calc_L1_latency(latency, 1); + ep_state->l1_acceptable_latency = latency; + } + } +} + +static unsigned int __pcie_aspm_check_state_one(struct pci_dev *pdev, + unsigned int state) +{ + struct pci_dev *parent_dev, *tmp_dev; + unsigned int latency, l1_latency = 0; + struct pcie_link_state *link_state; + struct endpoint_state *ep_state; + + parent_dev = pdev->bus->self; + link_state = parent_dev->link_state; + state &= link_state->support_state; + if (state == 0) + return 0; + ep_state = &link_state->endpoints[PCI_FUNC(pdev->devfn)]; + + /* + * Check latency for endpoint device. + * TBD: The latency from the endpoint to root complex vary per + * switch's upstream link state above the device. Here we just do a + * simple check which assumes all links above the device can be in L1 + * state, that is we just consider the worst case. If switch's upstream + * link can't be put into L0S/L1, then our check is too strictly. + */ + tmp_dev = pdev; + while (state & (PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1)) { + parent_dev = tmp_dev->bus->self; + link_state = parent_dev->link_state; + if (state & PCIE_LINK_STATE_L0S) { + latency = max_t(unsigned int, + link_state->l0s_upper_latency, + link_state->l0s_down_latency); + if (latency > ep_state->l0s_acceptable_latency) + state &= ~PCIE_LINK_STATE_L0S; + } + if (state & PCIE_LINK_STATE_L1) { + latency = max_t(unsigned int, + link_state->l1_upper_latency, + link_state->l1_down_latency); + if (latency + l1_latency > + ep_state->l1_acceptable_latency) + state &= ~PCIE_LINK_STATE_L1; + } + if (!parent_dev->bus->self) /* parent_dev is a root port */ + break; + else { + /* + * parent_dev is the downstream port of a switch, make + * tmp_dev the upstream port of the switch + */ + tmp_dev = parent_dev->bus->self; + /* + * every switch on the path to root complex need 1 more + * microsecond for L1. Spec doesn't mention L0S. + */ + if (state & PCIE_LINK_STATE_L1) + l1_latency += 1000; + } + } + return state; +} + +static unsigned int pcie_aspm_check_state(struct pci_dev *pdev, + unsigned int state) +{ + struct pci_dev *child_dev; + + /* If no child, disable the link */ + if (list_empty(&pdev->subordinate->devices)) + return 0; + list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { + if (child_dev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) { + /* + * If downstream component of a link is pci bridge, we + * disable ASPM for now for the link + * */ + state = 0; + break; + } + if ((child_dev->pcie_type != PCI_EXP_TYPE_ENDPOINT && + child_dev->pcie_type != PCI_EXP_TYPE_LEG_END)) + continue; + /* Device not in D0 doesn't need check latency */ + if (child_dev->current_state == PCI_D1 || + child_dev->current_state == PCI_D2 || + child_dev->current_state == PCI_D3hot || + child_dev->current_state == PCI_D3cold) + continue; + state = __pcie_aspm_check_state_one(child_dev, state); + } + return state; +} + +static void __pcie_aspm_config_one_dev(struct pci_dev *pdev, unsigned int state) +{ + u16 reg16; + int pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); + + pci_read_config_word(pdev, pos + PCI_EXP_LNKCTL, ®16); + reg16 &= ~0x3; + reg16 |= state; + pci_write_config_word(pdev, pos + PCI_EXP_LNKCTL, reg16); +} + +static void __pcie_aspm_config_link(struct pci_dev *pdev, unsigned int state) +{ + struct pci_dev *child_dev; + int valid = 1; + struct pcie_link_state *link_state = pdev->link_state; + + /* + * if the downstream component has pci bridge function, don't do ASPM + * now + */ + list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) { + if (child_dev->pcie_type == PCI_EXP_TYPE_PCI_BRIDGE) { + valid = 0; + break; + } + } + if (!valid) + return; + + /* + * spec 2.0 suggests all functions should be configured the same + * setting for ASPM. Enabling ASPM L1 should be done in upstream + * component first and then downstream, and vice versa for disabling + * ASPM L1. Spec doesn't mention L0S. + */ + if (state & PCIE_LINK_STATE_L1) + __pcie_aspm_config_one_dev(pdev, state); + + list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) + __pcie_aspm_config_one_dev(child_dev, state); + + if (!(state & PCIE_LINK_STATE_L1)) + __pcie_aspm_config_one_dev(pdev, state); + + link_state->enabled_state = state; +} + +static void __pcie_aspm_configure_link_state(struct pci_dev *pdev, + unsigned int state) +{ + struct pcie_link_state *link_state = pdev->link_state; + + if (link_state->support_state == 0) + return; + state &= PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1; + + /* state 0 means disabling aspm */ + state = pcie_aspm_check_state(pdev, state); + if (link_state->enabled_state == state) + return; + __pcie_aspm_config_link(pdev, state); +} + +/* + * pcie_aspm_configure_link_state: enable/disable PCI express link state + * @pdev: the root port or switch downstream port + */ +static void pcie_aspm_configure_link_state(struct pci_dev *pdev, + unsigned int state) +{ + down_read(&pci_bus_sem); + mutex_lock(&aspm_lock); + __pcie_aspm_configure_link_state(pdev, state); + mutex_unlock(&aspm_lock); + up_read(&pci_bus_sem); +} + +static void free_link_state(struct pci_dev *pdev) +{ + kfree(pdev->link_state); + pdev->link_state = NULL; +} + +/* + * pcie_aspm_init_link_state: Initiate PCI express link state. + * It is called after the pcie and its children devices are scaned. + * @pdev: the root port or switch downstream port + */ +void pcie_aspm_init_link_state(struct pci_dev *pdev) +{ + unsigned int state; + struct pcie_link_state *link_state; + int error = 0; + + if (aspm_disabled || !pdev->is_pcie || pdev->link_state) + return; + if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && + pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) + return; + down_read(&pci_bus_sem); + if (list_empty(&pdev->subordinate->devices)) + goto out; + + mutex_lock(&aspm_lock); + + link_state = kzalloc(sizeof(*link_state), GFP_KERNEL); + if (!link_state) + goto unlock_out; + pdev->link_state = link_state; + + pcie_aspm_configure_common_clock(pdev); + + pcie_aspm_cap_init(pdev); + + /* config link state to avoid BIOS error */ + state = pcie_aspm_check_state(pdev, policy_to_aspm_state(pdev)); + __pcie_aspm_config_link(pdev, state); + + pcie_check_clock_pm(pdev); + + link_state->pdev = pdev; + list_add(&link_state->sibiling, &link_list); + +unlock_out: + if (error) + free_link_state(pdev); + mutex_unlock(&aspm_lock); +out: + up_read(&pci_bus_sem); +} + +/* @pdev: the endpoint device */ +void pcie_aspm_exit_link_state(struct pci_dev *pdev) +{ + struct pci_dev *parent = pdev->bus->self; + struct pcie_link_state *link_state = parent->link_state; + + if (aspm_disabled || !pdev->is_pcie || !parent || !link_state) + return; + if (parent->pcie_type != PCI_EXP_TYPE_ROOT_PORT && + parent->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) + return; + down_read(&pci_bus_sem); + mutex_lock(&aspm_lock); + + /* + * All PCIe functions are in one slot, remove one function will remove + * the the whole slot, so just wait + */ + if (!list_empty(&parent->subordinate->devices)) + goto out; + + /* All functions are removed, so just disable ASPM for the link */ + __pcie_aspm_config_one_dev(parent, 0); + list_del(&link_state->sibiling); + /* Clock PM is for endpoint device */ + + free_link_state(parent); +out: + mutex_unlock(&aspm_lock); + up_read(&pci_bus_sem); +} + +/* @pdev: the root port or switch downstream port */ +void pcie_aspm_pm_state_change(struct pci_dev *pdev) +{ + struct pcie_link_state *link_state = pdev->link_state; + + if (aspm_disabled || !pdev->is_pcie || !pdev->link_state) + return; + if (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && + pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM) + return; + /* + * devices changed PM state, we should recheck if latency meets all + * functions' requirement + */ + pcie_aspm_configure_link_state(pdev, link_state->enabled_state); +} + +/* + * pci_disable_link_state - disable pci device's link state, so the link will + * never enter specific states + */ +void pci_disable_link_state(struct pci_dev *pdev, int state) +{ + struct pci_dev *parent = pdev->bus->self; + struct pcie_link_state *link_state; + + if (aspm_disabled || !pdev->is_pcie) + return; + if (pdev->pcie_type == PCI_EXP_TYPE_ROOT_PORT || + pdev->pcie_type == PCI_EXP_TYPE_DOWNSTREAM) + parent = pdev; + if (!parent) + return; + + down_read(&pci_bus_sem); + mutex_lock(&aspm_lock); + link_state = parent->link_state; + link_state->support_state &= + ~(state & (PCIE_LINK_STATE_L0S|PCIE_LINK_STATE_L1)); + if (state & PCIE_LINK_STATE_CLKPM) + link_state->clk_pm_capable = 0; + + __pcie_aspm_configure_link_state(parent, link_state->enabled_state); + if (!link_state->clk_pm_capable && link_state->clk_pm_enabled) + pcie_set_clock_pm(parent, 0); + mutex_unlock(&aspm_lock); + up_read(&pci_bus_sem); +} +EXPORT_SYMBOL(pci_disable_link_state); + +static int pcie_aspm_set_policy(const char *val, struct kernel_param *kp) +{ + int i; + struct pci_dev *pdev; + struct pcie_link_state *link_state; + + for (i = 0; i < ARRAY_SIZE(policy_str); i++) + if (!strncmp(val, policy_str[i], strlen(policy_str[i]))) + break; + if (i >= ARRAY_SIZE(policy_str)) + return -EINVAL; + if (i == aspm_policy) + return 0; + + down_read(&pci_bus_sem); + mutex_lock(&aspm_lock); + aspm_policy = i; + list_for_each_entry(link_state, &link_list, sibiling) { + pdev = link_state->pdev; + __pcie_aspm_configure_link_state(pdev, + policy_to_aspm_state(pdev)); + if (link_state->clk_pm_capable && + link_state->clk_pm_enabled != policy_to_clkpm_state(pdev)) + pcie_set_clock_pm(pdev, policy_to_clkpm_state(pdev)); + + } + mutex_unlock(&aspm_lock); + up_read(&pci_bus_sem); + return 0; +} + +static int pcie_aspm_get_policy(char *buffer, struct kernel_param *kp) +{ + int i, cnt = 0; + for (i = 0; i < ARRAY_SIZE(policy_str); i++) + if (i == aspm_policy) + cnt += sprintf(buffer + cnt, "[%s] ", policy_str[i]); + else + cnt += sprintf(buffer + cnt, "%s ", policy_str[i]); + return cnt; +} + +module_param_call(policy, pcie_aspm_set_policy, pcie_aspm_get_policy, + NULL, 0644); + +#ifdef CONFIG_PCIEASPM_DEBUG +static ssize_t link_state_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct pci_dev *pci_device = to_pci_dev(dev); + struct pcie_link_state *link_state = pci_device->link_state; + + return sprintf(buf, "%d\n", link_state->enabled_state); +} + +static ssize_t link_state_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t n) +{ + struct pci_dev *pci_device = to_pci_dev(dev); + int state; + + if (n < 1) + return -EINVAL; + state = buf[0]-'0'; + if (state >= 0 && state <= 3) { + /* setup link aspm state */ + pcie_aspm_configure_link_state(pci_device, state); + return n; + } + + return -EINVAL; +} + +static ssize_t clk_ctl_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct pci_dev *pci_device = to_pci_dev(dev); + struct pcie_link_state *link_state = pci_device->link_state; + + return sprintf(buf, "%d\n", link_state->clk_pm_enabled); +} + +static ssize_t clk_ctl_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t n) +{ + struct pci_dev *pci_device = to_pci_dev(dev); + int state; + + if (n < 1) + return -EINVAL; + state = buf[0]-'0'; + + down_read(&pci_bus_sem); + mutex_lock(&aspm_lock); + pcie_set_clock_pm(pci_device, !!state); + mutex_unlock(&aspm_lock); + up_read(&pci_bus_sem); + + return n; +} + +static DEVICE_ATTR(link_state, 0644, link_state_show, link_state_store); +static DEVICE_ATTR(clk_ctl, 0644, clk_ctl_show, clk_ctl_store); + +static char power_group[] = "power"; +void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev) +{ + struct pcie_link_state *link_state = pdev->link_state; + + if (!pdev->is_pcie || (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && + pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)) + return; + + if (link_state->support_state) + sysfs_add_file_to_group(&pdev->dev.kobj, + &dev_attr_link_state.attr, power_group); + if (link_state->clk_pm_capable) + sysfs_add_file_to_group(&pdev->dev.kobj, + &dev_attr_clk_ctl.attr, power_group); +} + +void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev) +{ + struct pcie_link_state *link_state = pdev->link_state; + + if (!pdev->is_pcie || (pdev->pcie_type != PCI_EXP_TYPE_ROOT_PORT && + pdev->pcie_type != PCI_EXP_TYPE_DOWNSTREAM)) + return; + + if (link_state->support_state) + sysfs_remove_file_from_group(&pdev->dev.kobj, + &dev_attr_link_state.attr, power_group); + if (link_state->clk_pm_capable) + sysfs_remove_file_from_group(&pdev->dev.kobj, + &dev_attr_clk_ctl.attr, power_group); +} +#endif + +static int __init pcie_aspm_disable(char *str) +{ + aspm_disabled = 1; + return 1; +} + +__setup("pcie_noaspm", pcie_aspm_disable); + +static int __init pcie_aspm_init(void) +{ + if (aspm_disabled) + return 0; + pci_osc_support_set(OSC_ACTIVE_STATE_PWR_SUPPORT| + OSC_CLOCK_PWR_CAPABILITY_SUPPORT); + return 0; +} + +fs_initcall(pcie_aspm_init); diff --git a/trunk/drivers/pci/probe.c b/trunk/drivers/pci/probe.c index 7f5dab34d315..8b505bd925aa 100644 --- a/trunk/drivers/pci/probe.c +++ b/trunk/drivers/pci/probe.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "pci.h" #define CARDBUS_LATENCY_TIMER 176 /* secondary latency timer */ @@ -433,7 +434,7 @@ pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr) return child; } -struct pci_bus *__ref pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr) +struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr) { struct pci_bus *child; @@ -948,7 +949,7 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus) up_write(&pci_bus_sem); } -struct pci_dev *__ref pci_scan_single_device(struct pci_bus *bus, int devfn) +struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn) { struct pci_dev *dev; @@ -1001,6 +1002,10 @@ int pci_scan_slot(struct pci_bus *bus, int devfn) break; } } + + if (bus->self) + pcie_aspm_init_link_state(bus->self); + return nr; } @@ -1040,6 +1045,20 @@ unsigned int pci_scan_child_bus(struct pci_bus *bus) return max; } +unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus) +{ + unsigned int max; + + max = pci_scan_child_bus(bus); + + /* + * Make the discovered devices available. + */ + pci_bus_add_devices(bus); + + return max; +} + struct pci_bus * pci_create_bus(struct device *parent, int bus, struct pci_ops *ops, void *sysdata) { @@ -1126,6 +1145,7 @@ EXPORT_SYMBOL(pci_scan_bus_parented); #ifdef CONFIG_HOTPLUG EXPORT_SYMBOL(pci_add_new_bus); +EXPORT_SYMBOL(pci_do_scan_bus); EXPORT_SYMBOL(pci_scan_slot); EXPORT_SYMBOL(pci_scan_bridge); EXPORT_SYMBOL_GPL(pci_scan_child_bus); diff --git a/trunk/drivers/pci/remove.c b/trunk/drivers/pci/remove.c index 9684e1bde277..ec4a82ba29a8 100644 --- a/trunk/drivers/pci/remove.c +++ b/trunk/drivers/pci/remove.c @@ -1,5 +1,6 @@ #include #include +#include #include "pci.h" static void pci_free_resources(struct pci_dev *dev) @@ -30,6 +31,9 @@ static void pci_stop_dev(struct pci_dev *dev) dev->global_list.next = dev->global_list.prev = NULL; up_write(&pci_bus_sem); } + + if (dev->bus->self) + pcie_aspm_exit_link_state(dev); } static void pci_destroy_dev(struct pci_dev *dev) diff --git a/trunk/drivers/pci/setup-bus.c b/trunk/drivers/pci/setup-bus.c index 262b0439abe9..8a7232feb553 100644 --- a/trunk/drivers/pci/setup-bus.c +++ b/trunk/drivers/pci/setup-bus.c @@ -456,7 +456,7 @@ pci_bus_size_cardbus(struct pci_bus *bus) } } -void __ref pci_bus_size_bridges(struct pci_bus *bus) +void pci_bus_size_bridges(struct pci_bus *bus) { struct pci_dev *dev; unsigned long mask, prefmask; @@ -511,7 +511,7 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus) } EXPORT_SYMBOL(pci_bus_size_bridges); -void __ref pci_bus_assign_resources(struct pci_bus *bus) +void pci_bus_assign_resources(struct pci_bus *bus) { struct pci_bus *b; struct pci_dev *dev; diff --git a/trunk/drivers/scsi/lpfc/lpfc_init.c b/trunk/drivers/scsi/lpfc/lpfc_init.c index 6cfeba7454d4..29b4cf9e059b 100644 --- a/trunk/drivers/scsi/lpfc/lpfc_init.c +++ b/trunk/drivers/scsi/lpfc/lpfc_init.c @@ -1894,7 +1894,7 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) uint16_t iotag; int bars = pci_select_bars(pdev, IORESOURCE_MEM); - if (pci_enable_device_mem(pdev)) + if (pci_enable_device_bars(pdev, bars)) goto out; if (pci_request_selected_regions(pdev, bars, LPFC_DRIVER_NAME)) goto out_disable_device; diff --git a/trunk/include/linux/aspm.h b/trunk/include/linux/aspm.h new file mode 100644 index 000000000000..f41a69895485 --- /dev/null +++ b/trunk/include/linux/aspm.h @@ -0,0 +1,44 @@ +/* + * aspm.h + * + * PCI Express ASPM defines and function prototypes + * + * Copyright (C) 2007 Intel Corp. + * Zhang Yanmin (yanmin.zhang@intel.com) + * Shaohua Li (shaohua.li@intel.com) + * + * For more information, please consult the following manuals (look at + * http://www.pcisig.com/ for how to get them): + * + * PCI Express Specification + */ + +#ifndef LINUX_ASPM_H +#define LINUX_ASPM_H + +#include + +#define PCIE_LINK_STATE_L0S 1 +#define PCIE_LINK_STATE_L1 2 +#define PCIE_LINK_STATE_CLKPM 4 + +#ifdef CONFIG_PCIEASPM +extern void pcie_aspm_init_link_state(struct pci_dev *pdev); +extern void pcie_aspm_exit_link_state(struct pci_dev *pdev); +extern void pcie_aspm_pm_state_change(struct pci_dev *pdev); +extern void pci_disable_link_state(struct pci_dev *pdev, int state); +#else +#define pcie_aspm_init_link_state(pdev) do {} while (0) +#define pcie_aspm_exit_link_state(pdev) do {} while (0) +#define pcie_aspm_pm_state_change(pdev) do {} while (0) +#define pci_disable_link_state(pdev, state) do {} while (0) +#endif + +#ifdef CONFIG_PCIEASPM_DEBUG /* this depends on CONFIG_PCIEASPM */ +extern void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev); +extern void pcie_aspm_remove_sysfs_dev_files(struct pci_dev *pdev); +#else +#define pcie_aspm_create_sysfs_dev_files(pdev) do {} while (0) +#define pcie_aspm_remove_sysfs_dev_files(pdev) do {} while (0) +#endif +#endif /* LINUX_ASPM_H */ diff --git a/trunk/include/linux/device.h b/trunk/include/linux/device.h index 479c0b31593c..db375be333c7 100644 --- a/trunk/include/linux/device.h +++ b/trunk/include/linux/device.h @@ -534,17 +534,11 @@ extern struct device *device_create(struct class *cls, struct device *parent, extern void device_destroy(struct class *cls, dev_t devt); #ifdef CONFIG_PM_SLEEP extern void destroy_suspended_device(struct class *cls, dev_t devt); -extern void device_pm_schedule_removal(struct device *); #else /* !CONFIG_PM_SLEEP */ static inline void destroy_suspended_device(struct class *cls, dev_t devt) { device_destroy(cls, devt); } - -static inline void device_pm_schedule_removal(struct device *dev) -{ - device_unregister(dev); -} #endif /* !CONFIG_PM_SLEEP */ /* diff --git a/trunk/include/linux/pci.h b/trunk/include/linux/pci.h index cee75c0ff6e7..4f96f1d94ac4 100644 --- a/trunk/include/linux/pci.h +++ b/trunk/include/linux/pci.h @@ -128,6 +128,7 @@ struct pci_cap_saved_state { u32 data[0]; }; +struct pcie_link_state; /* * The pci_dev structure is used to describe PCI devices. */ @@ -163,6 +164,10 @@ struct pci_dev { this is D0-D3, D0 being fully functional, and D3 being off. */ +#ifdef CONFIG_PCIEASPM + struct pcie_link_state *link_state; /* ASPM link state. */ +#endif + pci_channel_state_t error_state; /* current connectivity state */ struct device dev; /* Generic device interface */ diff --git a/trunk/include/linux/pci_regs.h b/trunk/include/linux/pci_regs.h index c1914a8b94a9..c0c1223c9194 100644 --- a/trunk/include/linux/pci_regs.h +++ b/trunk/include/linux/pci_regs.h @@ -395,9 +395,17 @@ #define PCI_EXP_DEVSTA_AUXPD 0x10 /* AUX Power Detected */ #define PCI_EXP_DEVSTA_TRPND 0x20 /* Transactions Pending */ #define PCI_EXP_LNKCAP 12 /* Link Capabilities */ +#define PCI_EXP_LNKCAP_ASPMS 0xc00 /* ASPM Support */ +#define PCI_EXP_LNKCAP_L0SEL 0x7000 /* L0s Exit Latency */ +#define PCI_EXP_LNKCAP_L1EL 0x38000 /* L1 Exit Latency */ +#define PCI_EXP_LNKCAP_CLKPM 0x40000 /* L1 Clock Power Management */ #define PCI_EXP_LNKCTL 16 /* Link Control */ +#define PCI_EXP_LNKCTL_RL 0x20 /* Retrain Link */ +#define PCI_EXP_LNKCTL_CCC 0x40 /* Common Clock COnfiguration */ #define PCI_EXP_LNKCTL_CLKREQ_EN 0x100 /* Enable clkreq */ #define PCI_EXP_LNKSTA 18 /* Link Status */ +#define PCI_EXP_LNKSTA_LT 0x800 /* Link Training */ +#define PCI_EXP_LNKSTA_SLC 0x1000 /* Slot Clock Configuration */ #define PCI_EXP_SLTCAP 20 /* Slot Capabilities */ #define PCI_EXP_SLTCTL 24 /* Slot Control */ #define PCI_EXP_SLTSTA 26 /* Slot Status */ diff --git a/trunk/kernel/Makefile b/trunk/kernel/Makefile index db9af707ff5b..8885627ea021 100644 --- a/trunk/kernel/Makefile +++ b/trunk/kernel/Makefile @@ -9,7 +9,7 @@ obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \ rcupdate.o extable.o params.o posix-timers.o \ kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \ hrtimer.o rwsem.o latency.o nsproxy.o srcu.o \ - utsname.o notifier.o ksysfs.o + utsname.o notifier.o obj-$(CONFIG_SYSCTL) += sysctl_check.o obj-$(CONFIG_STACKTRACE) += stacktrace.o @@ -49,6 +49,7 @@ obj-$(CONFIG_AUDIT) += audit.o auditfilter.o obj-$(CONFIG_AUDITSYSCALL) += auditsc.o obj-$(CONFIG_AUDIT_TREE) += audit_tree.o obj-$(CONFIG_KPROBES) += kprobes.o +obj-$(CONFIG_SYSFS) += ksysfs.o obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o obj-$(CONFIG_GENERIC_HARDIRQS) += irq/ obj-$(CONFIG_SECCOMP) += seccomp.o diff --git a/trunk/lib/kobject.c b/trunk/lib/kobject.c index d784daeb8571..1d63ead1815e 100644 --- a/trunk/lib/kobject.c +++ b/trunk/lib/kobject.c @@ -637,7 +637,7 @@ struct kobject *kobject_create(void) * @name: the name for the kset * @parent: the parent kobject of this kobject, if any. * - * This function creates a kobject structure dynamically and registers it + * This function creates a kset structure dynamically and registers it * with sysfs. When you are finished with this structure, call * kobject_put() and the structure will be dynamically freed when * it is no longer being used.