From 536acc085c641ff8ba46c2c0e97b5e137cbc22d6 Mon Sep 17 00:00:00 2001 From: Zefir Kurtisi Date: Mon, 7 May 2012 11:21:59 +0200 Subject: nl80211: fix typos in comments Signed-off-by: Zefir Kurtisi Signed-off-by: John W. Linville --- include/linux/nl80211.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 2540e86d99ab..f296a64d103b 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -1994,9 +1994,9 @@ enum nl80211_reg_rule_flags { * enum nl80211_dfs_regions - regulatory DFS regions * * @NL80211_DFS_UNSET: Country has no DFS master region specified - * @NL80211_DFS_FCC_: Country follows DFS master rules from FCC - * @NL80211_DFS_FCC_: Country follows DFS master rules from ETSI - * @NL80211_DFS_JP_: Country follows DFS master rules from JP/MKK/Telec + * @NL80211_DFS_FCC: Country follows DFS master rules from FCC + * @NL80211_DFS_ETSI: Country follows DFS master rules from ETSI + * @NL80211_DFS_JP: Country follows DFS master rules from JP/MKK/Telec */ enum nl80211_dfs_regions { NL80211_DFS_UNSET = 0, -- cgit From bbed0deefbb4bb1ab09e0dbc29e00fda86bb7838 Mon Sep 17 00:00:00 2001 From: Eric Lapuyade Date: Mon, 7 May 2012 12:31:29 +0200 Subject: NFC: HCI based pn544 driver This is an NFC driver for NXP pn544. Unlike pn544.c, this one is based on the NFC HCI and SHDLC kernel layers. Signed-off-by: Eric Lapuyade Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- drivers/nfc/Kconfig | 13 + drivers/nfc/Makefile | 1 + drivers/nfc/pn544_hci.c | 947 ++++++++++++++++++++++++++++++++++++++++++++++ include/linux/nfc/pn544.h | 7 + 4 files changed, 968 insertions(+) create mode 100644 drivers/nfc/pn544_hci.c (limited to 'include/linux') diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig index 5af959274d4e..3b20b73ee649 100644 --- a/drivers/nfc/Kconfig +++ b/drivers/nfc/Kconfig @@ -17,6 +17,19 @@ config PN544_NFC To compile this driver as a module, choose m here. The module will be called pn544. +config PN544_HCI_NFC + tristate "HCI PN544 NFC driver" + depends on I2C && NFC_SHDLC + select CRC_CCITT + default n + ---help--- + NXP PN544 i2c driver. + This is a driver based on the SHDLC and HCI NFC kernel layers and + will thus not work with NXP libnfc library. + + To compile this driver as a module, choose m here. The module will + be called pn544_hci. + config NFC_PN533 tristate "NXP PN533 USB driver" depends on USB diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile index ab99e8572f02..473e44cef612 100644 --- a/drivers/nfc/Makefile +++ b/drivers/nfc/Makefile @@ -3,6 +3,7 @@ # obj-$(CONFIG_PN544_NFC) += pn544.o +obj-$(CONFIG_PN544_HCI_NFC) += pn544_hci.o obj-$(CONFIG_NFC_PN533) += pn533.o obj-$(CONFIG_NFC_WILINK) += nfcwilink.o diff --git a/drivers/nfc/pn544_hci.c b/drivers/nfc/pn544_hci.c new file mode 100644 index 000000000000..46f4a9f9f5e4 --- /dev/null +++ b/drivers/nfc/pn544_hci.c @@ -0,0 +1,947 @@ +/* + * HCI based Driver for NXP PN544 NFC Chip + * + * Copyright (C) 2012 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#define DRIVER_DESC "HCI NFC driver for PN544" + +#define PN544_HCI_DRIVER_NAME "pn544_hci" + +/* Timing restrictions (ms) */ +#define PN544_HCI_RESETVEN_TIME 30 + +static struct i2c_device_id pn544_hci_id_table[] = { + {"pn544", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, pn544_hci_id_table); + +#define HCI_MODE 0 +#define FW_MODE 1 + +/* framing in HCI mode */ +#define PN544_HCI_LLC_LEN 1 +#define PN544_HCI_LLC_CRC 2 +#define PN544_HCI_LLC_LEN_CRC (PN544_HCI_LLC_LEN + PN544_HCI_LLC_CRC) +#define PN544_HCI_LLC_MIN_SIZE (1 + PN544_HCI_LLC_LEN_CRC) +#define PN544_HCI_LLC_MAX_PAYLOAD 29 +#define PN544_HCI_LLC_MAX_SIZE (PN544_HCI_LLC_LEN_CRC + 1 + \ + PN544_HCI_LLC_MAX_PAYLOAD) + +enum pn544_state { + PN544_ST_COLD, + PN544_ST_FW_READY, + PN544_ST_READY, +}; + +#define FULL_VERSION_LEN 11 + +/* Proprietary commands */ +#define PN544_WRITE 0x3f + +/* Proprietary gates, events, commands and registers */ + +/* NFC_HCI_RF_READER_A_GATE additional registers and commands */ +#define PN544_RF_READER_A_AUTO_ACTIVATION 0x10 +#define PN544_RF_READER_A_CMD_CONTINUE_ACTIVATION 0x12 +#define PN544_MIFARE_CMD 0x21 + +/* Commands that apply to all RF readers */ +#define PN544_RF_READER_CMD_PRESENCE_CHECK 0x30 +#define PN544_RF_READER_CMD_ACTIVATE_NEXT 0x32 + +/* NFC_HCI_ID_MGMT_GATE additional registers */ +#define PN544_ID_MGMT_FULL_VERSION_SW 0x10 + +#define PN544_RF_READER_ISO15693_GATE 0x12 + +#define PN544_RF_READER_F_GATE 0x14 +#define PN544_FELICA_ID 0x04 +#define PN544_FELICA_RAW 0x20 + +#define PN544_RF_READER_JEWEL_GATE 0x15 +#define PN544_JEWEL_RAW_CMD 0x23 + +#define PN544_RF_READER_NFCIP1_INITIATOR_GATE 0x30 +#define PN544_RF_READER_NFCIP1_TARGET_GATE 0x31 + +#define PN544_SYS_MGMT_GATE 0x90 +#define PN544_SYS_MGMT_INFO_NOTIFICATION 0x02 + +#define PN544_POLLING_LOOP_MGMT_GATE 0x94 +#define PN544_PL_RDPHASES 0x06 +#define PN544_PL_EMULATION 0x07 +#define PN544_PL_NFCT_DEACTIVATED 0x09 + +#define PN544_SWP_MGMT_GATE 0xA0 + +#define PN544_NFC_WI_MGMT_GATE 0xA1 + +static u8 pn544_custom_gates[] = { + PN544_SYS_MGMT_GATE, + PN544_SWP_MGMT_GATE, + PN544_POLLING_LOOP_MGMT_GATE, + PN544_NFC_WI_MGMT_GATE, + PN544_RF_READER_F_GATE, + PN544_RF_READER_JEWEL_GATE, + PN544_RF_READER_ISO15693_GATE, + PN544_RF_READER_NFCIP1_INITIATOR_GATE, + PN544_RF_READER_NFCIP1_TARGET_GATE +}; + +/* Largest headroom needed for outgoing custom commands */ +#define PN544_CMDS_HEADROOM 2 + +struct pn544_hci_info { + struct i2c_client *i2c_dev; + struct nfc_shdlc *shdlc; + + enum pn544_state state; + + struct mutex info_lock; + + unsigned int gpio_en; + unsigned int gpio_irq; + unsigned int gpio_fw; + unsigned int en_polarity; + + int hard_fault; /* + * < 0 if hardware error occured (e.g. i2c err) + * and prevents normal operation. + */ +}; + +static void pn544_hci_platform_init(struct pn544_hci_info *info) +{ + int polarity, retry, ret; + char rset_cmd[] = { 0x05, 0xF9, 0x04, 0x00, 0xC3, 0xE5 }; + int count = sizeof(rset_cmd); + + pr_info(DRIVER_DESC ": %s\n", __func__); + dev_info(&info->i2c_dev->dev, "Detecting nfc_en polarity\n"); + + /* Disable fw download */ + gpio_set_value(info->gpio_fw, 0); + + for (polarity = 0; polarity < 2; polarity++) { + info->en_polarity = polarity; + retry = 3; + while (retry--) { + /* power off */ + gpio_set_value(info->gpio_en, !info->en_polarity); + usleep_range(10000, 15000); + + /* power on */ + gpio_set_value(info->gpio_en, info->en_polarity); + usleep_range(10000, 15000); + + /* send reset */ + dev_dbg(&info->i2c_dev->dev, "Sending reset cmd\n"); + ret = i2c_master_send(info->i2c_dev, rset_cmd, count); + if (ret == count) { + dev_info(&info->i2c_dev->dev, + "nfc_en polarity : active %s\n", + (polarity == 0 ? "low" : "high")); + goto out; + } + } + } + + dev_err(&info->i2c_dev->dev, + "Could not detect nfc_en polarity, fallback to active high\n"); + +out: + gpio_set_value(info->gpio_en, !info->en_polarity); +} + +static int pn544_hci_enable(struct pn544_hci_info *info, int mode) +{ + pr_info(DRIVER_DESC ": %s\n", __func__); + + gpio_set_value(info->gpio_fw, 0); + gpio_set_value(info->gpio_en, info->en_polarity); + usleep_range(10000, 15000); + + return 0; +} + +static void pn544_hci_disable(struct pn544_hci_info *info) +{ + pr_info(DRIVER_DESC ": %s\n", __func__); + + gpio_set_value(info->gpio_fw, 0); + gpio_set_value(info->gpio_en, !info->en_polarity); + usleep_range(10000, 15000); + + gpio_set_value(info->gpio_en, info->en_polarity); + usleep_range(10000, 15000); + + gpio_set_value(info->gpio_en, !info->en_polarity); + usleep_range(10000, 15000); +} + +static int pn544_hci_i2c_write(struct i2c_client *client, u8 *buf, int len) +{ + int r; + + usleep_range(3000, 6000); + + r = i2c_master_send(client, buf, len); + + if (r == -EREMOTEIO) { /* Retry, chip was in standby */ + usleep_range(6000, 10000); + r = i2c_master_send(client, buf, len); + } + + if (r >= 0 && r != len) + r = -EREMOTEIO; + + return r; +} + +static int check_crc(u8 *buf, int buflen) +{ + u8 len; + u16 crc; + + len = buf[0] + 1; + crc = crc_ccitt(0xffff, buf, len - 2); + crc = ~crc; + + if (buf[len - 2] != (crc & 0xff) || buf[len - 1] != (crc >> 8)) { + pr_err(PN544_HCI_DRIVER_NAME ": CRC error 0x%x != 0x%x 0x%x\n", + crc, buf[len - 1], buf[len - 2]); + + pr_info(DRIVER_DESC ": %s : BAD CRC\n", __func__); + print_hex_dump(KERN_DEBUG, "crc: ", DUMP_PREFIX_NONE, + 16, 2, buf, buflen, false); + return -EPERM; + } + return 0; +} + +/* + * Reads an shdlc frame and returns it in a newly allocated sk_buff. Guarantees + * that i2c bus will be flushed and that next read will start on a new frame. + * returned skb contains only LLC header and payload. + * returns: + * -EREMOTEIO : i2c read error (fatal) + * -EBADMSG : frame was incorrect and discarded + * -ENOMEM : cannot allocate skb, frame dropped + */ +static int pn544_hci_i2c_read(struct i2c_client *client, struct sk_buff **skb) +{ + int r; + u8 len; + u8 tmp[PN544_HCI_LLC_MAX_SIZE - 1]; + + r = i2c_master_recv(client, &len, 1); + if (r != 1) { + dev_err(&client->dev, "cannot read len byte\n"); + return -EREMOTEIO; + } + + if ((len < (PN544_HCI_LLC_MIN_SIZE - 1)) || + (len > (PN544_HCI_LLC_MAX_SIZE - 1))) { + dev_err(&client->dev, "invalid len byte\n"); + r = -EBADMSG; + goto flush; + } + + *skb = alloc_skb(1 + len, GFP_KERNEL); + if (*skb == NULL) { + r = -ENOMEM; + goto flush; + } + + *skb_put(*skb, 1) = len; + + r = i2c_master_recv(client, skb_put(*skb, len), len); + if (r != len) { + kfree_skb(*skb); + return -EREMOTEIO; + } + + r = check_crc((*skb)->data, (*skb)->len); + if (r != 0) { + kfree_skb(*skb); + r = -EBADMSG; + goto flush; + } + + skb_pull(*skb, 1); + skb_trim(*skb, (*skb)->len - 2); + + usleep_range(3000, 6000); + + return 0; + +flush: + if (i2c_master_recv(client, tmp, sizeof(tmp)) < 0) + r = -EREMOTEIO; + + usleep_range(3000, 6000); + + return r; +} + +/* + * Reads an shdlc frame from the chip. This is not as straightforward as it + * seems. There are cases where we could loose the frame start synchronization. + * The frame format is len-data-crc, and corruption can occur anywhere while + * transiting on i2c bus, such that we could read an invalid len. + * In order to recover synchronization with the next frame, we must be sure + * to read the real amount of data without using the len byte. We do this by + * assuming the following: + * - the chip will always present only one single complete frame on the bus + * before triggering the interrupt + * - the chip will not present a new frame until we have completely read + * the previous one (or until we have handled the interrupt). + * The tricky case is when we read a corrupted len that is less than the real + * len. We must detect this here in order to determine that we need to flush + * the bus. This is the reason why we check the crc here. + */ +static irqreturn_t pn544_hci_irq_thread_fn(int irq, void *dev_id) +{ + struct pn544_hci_info *info = dev_id; + struct i2c_client *client = info->i2c_dev; + struct sk_buff *skb = NULL; + int r; + + BUG_ON(!info); + BUG_ON(irq != info->i2c_dev->irq); + + dev_dbg(&client->dev, "IRQ\n"); + + if (info->hard_fault != 0) + return IRQ_HANDLED; + + r = pn544_hci_i2c_read(client, &skb); + if (r == -EREMOTEIO) { + info->hard_fault = r; + + nfc_shdlc_recv_frame(info->shdlc, NULL); + + return IRQ_HANDLED; + } else if ((r == -ENOMEM) || (r == -EBADMSG)) { + return IRQ_HANDLED; + } + + nfc_shdlc_recv_frame(info->shdlc, skb); + + return IRQ_HANDLED; +} + +static int pn544_hci_open(struct nfc_shdlc *shdlc) +{ + struct pn544_hci_info *info = nfc_shdlc_get_clientdata(shdlc); + int r = 0; + + mutex_lock(&info->info_lock); + + if (info->state != PN544_ST_COLD) { + r = -EBUSY; + goto out; + } + + r = pn544_hci_enable(info, HCI_MODE); + +out: + mutex_unlock(&info->info_lock); + return r; +} + +static void pn544_hci_close(struct nfc_shdlc *shdlc) +{ + struct pn544_hci_info *info = nfc_shdlc_get_clientdata(shdlc); + + mutex_lock(&info->info_lock); + + if (info->state == PN544_ST_COLD) + goto out; + + pn544_hci_disable(info); + +out: + mutex_unlock(&info->info_lock); +} + +static int pn544_hci_ready(struct nfc_shdlc *shdlc) +{ + struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc); + struct sk_buff *skb; + static struct hw_config { + u8 adr[2]; + u8 value; + } hw_config[] = { + {{0x9f, 0x9a}, 0x00}, + + {{0x98, 0x10}, 0xbc}, + + {{0x9e, 0x71}, 0x00}, + + {{0x98, 0x09}, 0x00}, + + {{0x9e, 0xb4}, 0x00}, + + {{0x9e, 0xd9}, 0xff}, + {{0x9e, 0xda}, 0xff}, + {{0x9e, 0xdb}, 0x23}, + {{0x9e, 0xdc}, 0x21}, + {{0x9e, 0xdd}, 0x22}, + {{0x9e, 0xde}, 0x24}, + + {{0x9c, 0x01}, 0x08}, + + {{0x9e, 0xaa}, 0x01}, + + {{0x9b, 0xd1}, 0x0d}, + {{0x9b, 0xd2}, 0x24}, + {{0x9b, 0xd3}, 0x0a}, + {{0x9b, 0xd4}, 0x22}, + {{0x9b, 0xd5}, 0x08}, + {{0x9b, 0xd6}, 0x1e}, + {{0x9b, 0xdd}, 0x1c}, + + {{0x9b, 0x84}, 0x13}, + {{0x99, 0x81}, 0x7f}, + {{0x99, 0x31}, 0x70}, + + {{0x98, 0x00}, 0x3f}, + + {{0x9f, 0x09}, 0x00}, + + {{0x9f, 0x0a}, 0x05}, + + {{0x9e, 0xd1}, 0xa1}, + {{0x99, 0x23}, 0x00}, + + {{0x9e, 0x74}, 0x80}, + + {{0x9f, 0x28}, 0x10}, + + {{0x9f, 0x35}, 0x14}, + + {{0x9f, 0x36}, 0x60}, + + {{0x9c, 0x31}, 0x00}, + + {{0x9c, 0x32}, 0xc8}, + + {{0x9c, 0x19}, 0x40}, + + {{0x9c, 0x1a}, 0x40}, + + {{0x9c, 0x0c}, 0x00}, + + {{0x9c, 0x0d}, 0x00}, + + {{0x9c, 0x12}, 0x00}, + + {{0x9c, 0x13}, 0x00}, + + {{0x98, 0xa2}, 0x0e}, + + {{0x98, 0x93}, 0x40}, + + {{0x98, 0x7d}, 0x02}, + {{0x98, 0x7e}, 0x00}, + {{0x9f, 0xc8}, 0x01}, + }; + struct hw_config *p = hw_config; + int count = ARRAY_SIZE(hw_config); + struct sk_buff *res_skb; + u8 param[4]; + int r; + + param[0] = 0; + while (count--) { + param[1] = p->adr[0]; + param[2] = p->adr[1]; + param[3] = p->value; + + r = nfc_hci_send_cmd(hdev, PN544_SYS_MGMT_GATE, PN544_WRITE, + param, 4, &res_skb); + if (r < 0) + return r; + + if (res_skb->len != 1) { + kfree_skb(res_skb); + return -EPROTO; + } + + if (res_skb->data[0] != p->value) { + kfree_skb(res_skb); + return -EIO; + } + + kfree_skb(res_skb); + + p++; + } + + param[0] = NFC_HCI_UICC_HOST_ID; + r = nfc_hci_set_param(hdev, NFC_HCI_ADMIN_GATE, + NFC_HCI_ADMIN_WHITELIST, param, 1); + if (r < 0) + return r; + + param[0] = 0x3d; + r = nfc_hci_set_param(hdev, PN544_SYS_MGMT_GATE, + PN544_SYS_MGMT_INFO_NOTIFICATION, param, 1); + if (r < 0) + return r; + + param[0] = 0x0; + r = nfc_hci_set_param(hdev, NFC_HCI_RF_READER_A_GATE, + PN544_RF_READER_A_AUTO_ACTIVATION, param, 1); + if (r < 0) + return r; + + r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, + NFC_HCI_EVT_END_OPERATION, NULL, 0); + if (r < 0) + return r; + + param[0] = 0x1; + r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE, + PN544_PL_NFCT_DEACTIVATED, param, 1); + if (r < 0) + return r; + + param[0] = 0x0; + r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE, + PN544_PL_RDPHASES, param, 1); + if (r < 0) + return r; + + r = nfc_hci_get_param(hdev, NFC_HCI_ID_MGMT_GATE, + PN544_ID_MGMT_FULL_VERSION_SW, &skb); + if (r < 0) + return r; + + if (skb->len != FULL_VERSION_LEN) { + kfree_skb(skb); + return -EINVAL; + } + + print_hex_dump(KERN_DEBUG, "FULL VERSION SOFTWARE INFO: ", + DUMP_PREFIX_NONE, 16, 1, + skb->data, FULL_VERSION_LEN, false); + + kfree_skb(skb); + + return 0; +} + +static int pn544_hci_xmit(struct nfc_shdlc *shdlc, struct sk_buff *skb) +{ + struct pn544_hci_info *info = nfc_shdlc_get_clientdata(shdlc); + struct i2c_client *client = info->i2c_dev; + + if (info->hard_fault != 0) + return info->hard_fault; + + return pn544_hci_i2c_write(client, skb->data, skb->len); +} + +static int pn544_hci_start_poll(struct nfc_shdlc *shdlc, u32 protocols) +{ + struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc); + u8 phases = 0; + int r; + u8 duration[2]; + u8 activated; + + pr_info(DRIVER_DESC ": %s protocols = %d\n", __func__, protocols); + + r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, + NFC_HCI_EVT_END_OPERATION, NULL, 0); + if (r < 0) + return r; + + duration[0] = 0x18; + duration[1] = 0x6a; + r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE, + PN544_PL_EMULATION, duration, 2); + if (r < 0) + return r; + + activated = 0; + r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE, + PN544_PL_NFCT_DEACTIVATED, &activated, 1); + if (r < 0) + return r; + + if (protocols & (NFC_PROTO_ISO14443_MASK | NFC_PROTO_MIFARE_MASK | + NFC_PROTO_JEWEL_MASK)) + phases |= 1; /* Type A */ + if (protocols & NFC_PROTO_FELICA_MASK) { + phases |= (1 << 2); /* Type F 212 */ + phases |= (1 << 3); /* Type F 424 */ + } + + phases |= (1 << 5); /* NFC active */ + + r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE, + PN544_PL_RDPHASES, &phases, 1); + if (r < 0) + return r; + + r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, + NFC_HCI_EVT_READER_REQUESTED, NULL, 0); + if (r < 0) + nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, + NFC_HCI_EVT_END_OPERATION, NULL, 0); + + return r; +} + +static int pn544_hci_target_from_gate(struct nfc_shdlc *shdlc, u8 gate, + struct nfc_target *target) +{ + switch (gate) { + case PN544_RF_READER_F_GATE: + target->supported_protocols = NFC_PROTO_FELICA_MASK; + break; + case PN544_RF_READER_JEWEL_GATE: + target->supported_protocols = NFC_PROTO_JEWEL_MASK; + target->sens_res = 0x0c00; + break; + default: + return -EPROTO; + } + + return 0; +} + +static int pn544_hci_complete_target_discovered(struct nfc_shdlc *shdlc, + u8 gate, + struct nfc_target *target) +{ + struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc); + struct sk_buff *uid_skb; + int r = 0; + + if (target->supported_protocols & NFC_PROTO_MIFARE_MASK) { + if (target->nfcid1_len != 4 && target->nfcid1_len != 7 && + target->nfcid1_len != 10) + return -EPROTO; + + r = nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE, + PN544_RF_READER_CMD_ACTIVATE_NEXT, + target->nfcid1, target->nfcid1_len, NULL); + } else if (target->supported_protocols & NFC_PROTO_FELICA_MASK) { + r = nfc_hci_get_param(hdev, PN544_RF_READER_F_GATE, + PN544_FELICA_ID, &uid_skb); + if (r < 0) + return r; + + if (uid_skb->len != 8) { + kfree_skb(uid_skb); + return -EPROTO; + } + + r = nfc_hci_send_cmd(hdev, PN544_RF_READER_F_GATE, + PN544_RF_READER_CMD_ACTIVATE_NEXT, + uid_skb->data, uid_skb->len, NULL); + kfree_skb(uid_skb); + } else if (target->supported_protocols & NFC_PROTO_ISO14443_MASK) { + /* + * TODO: maybe other ISO 14443 require some kind of continue + * activation, but for now we've seen only this one below. + */ + if (target->sens_res == 0x4403) /* Type 4 Mifare DESFire */ + r = nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE, + PN544_RF_READER_A_CMD_CONTINUE_ACTIVATION, + NULL, 0, NULL); + } + + return r; +} + +#define MIFARE_CMD_AUTH_KEY_A 0x60 +#define MIFARE_CMD_AUTH_KEY_B 0x61 +#define MIFARE_CMD_HEADER 2 +#define MIFARE_UID_LEN 4 +#define MIFARE_KEY_LEN 6 +#define MIFARE_CMD_LEN 12 +/* + * Returns: + * <= 0: driver handled the data exchange + * 1: driver doesn't especially handle, please do standard processing + */ +static int pn544_hci_data_exchange(struct nfc_shdlc *shdlc, + struct nfc_target *target, + struct sk_buff *skb, + struct sk_buff **res_skb) +{ + struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc); + int r; + + pr_info(DRIVER_DESC ": %s for gate=%d\n", __func__, + target->hci_reader_gate); + + switch (target->hci_reader_gate) { + case NFC_HCI_RF_READER_A_GATE: + if (target->supported_protocols & NFC_PROTO_MIFARE_MASK) { + /* + * It seems that pn544 is inverting key and UID for + * MIFARE authentication commands. + */ + if (skb->len == MIFARE_CMD_LEN && + (skb->data[0] == MIFARE_CMD_AUTH_KEY_A || + skb->data[0] == MIFARE_CMD_AUTH_KEY_B)) { + u8 uid[MIFARE_UID_LEN]; + u8 *data = skb->data + MIFARE_CMD_HEADER; + + memcpy(uid, data + MIFARE_KEY_LEN, + MIFARE_UID_LEN); + memmove(data + MIFARE_UID_LEN, data, + MIFARE_KEY_LEN); + memcpy(data, uid, MIFARE_UID_LEN); + } + + return nfc_hci_send_cmd(hdev, target->hci_reader_gate, + PN544_MIFARE_CMD, + skb->data, skb->len, res_skb); + } else + return 1; + case PN544_RF_READER_F_GATE: + *skb_push(skb, 1) = 0; + *skb_push(skb, 1) = 0; + + r = nfc_hci_send_cmd(hdev, target->hci_reader_gate, + PN544_FELICA_RAW, + skb->data, skb->len, res_skb); + if (r == 0) + skb_pull(*res_skb, 1); + return r; + case PN544_RF_READER_JEWEL_GATE: + return nfc_hci_send_cmd(hdev, target->hci_reader_gate, + PN544_JEWEL_RAW_CMD, + skb->data, skb->len, res_skb); + default: + return 1; + } +} + +static int pn544_hci_check_presence(struct nfc_shdlc *shdlc, + struct nfc_target *target) +{ + struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc); + + return nfc_hci_send_cmd(hdev, target->hci_reader_gate, + PN544_RF_READER_CMD_PRESENCE_CHECK, + NULL, 0, NULL); +} + +static struct nfc_shdlc_ops pn544_shdlc_ops = { + .open = pn544_hci_open, + .close = pn544_hci_close, + .hci_ready = pn544_hci_ready, + .xmit = pn544_hci_xmit, + .start_poll = pn544_hci_start_poll, + .target_from_gate = pn544_hci_target_from_gate, + .complete_target_discovered = pn544_hci_complete_target_discovered, + .data_exchange = pn544_hci_data_exchange, + .check_presence = pn544_hci_check_presence, +}; + +static int __devinit pn544_hci_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct pn544_hci_info *info; + struct pn544_nfc_platform_data *pdata; + int r = 0; + u32 protocols; + struct nfc_hci_init_data init_data; + + dev_dbg(&client->dev, "%s\n", __func__); + dev_dbg(&client->dev, "IRQ: %d\n", client->irq); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "Need I2C_FUNC_I2C\n"); + return -ENODEV; + } + + info = kzalloc(sizeof(struct pn544_hci_info), GFP_KERNEL); + if (!info) { + dev_err(&client->dev, + "Cannot allocate memory for pn544_hci_info.\n"); + r = -ENOMEM; + goto err_info_alloc; + } + + info->i2c_dev = client; + info->state = PN544_ST_COLD; + mutex_init(&info->info_lock); + i2c_set_clientdata(client, info); + + pdata = client->dev.platform_data; + if (pdata == NULL) { + dev_err(&client->dev, "No platform data\n"); + r = -EINVAL; + goto err_pdata; + } + + if (pdata->request_resources == NULL) { + dev_err(&client->dev, "request_resources() missing\n"); + r = -EINVAL; + goto err_pdata; + } + + r = pdata->request_resources(client); + if (r) { + dev_err(&client->dev, "Cannot get platform resources\n"); + goto err_pdata; + } + + info->gpio_en = pdata->get_gpio(NFC_GPIO_ENABLE); + info->gpio_fw = pdata->get_gpio(NFC_GPIO_FW_RESET); + info->gpio_irq = pdata->get_gpio(NFC_GPIO_IRQ); + + pn544_hci_platform_init(info); + + r = request_threaded_irq(client->irq, NULL, pn544_hci_irq_thread_fn, + IRQF_TRIGGER_RISING, PN544_HCI_DRIVER_NAME, + info); + if (r < 0) { + dev_err(&client->dev, "Unable to register IRQ handler\n"); + goto err_rti; + } + + init_data.gate_count = ARRAY_SIZE(pn544_custom_gates); + + memcpy(init_data.gates, pn544_custom_gates, + ARRAY_SIZE(pn544_custom_gates)); + + /* + * TODO: Session id must include the driver name + some bus addr + * persistent info to discriminate 2 identical chips + */ + strcpy(init_data.session_id, "ID544HCI"); + + protocols = NFC_PROTO_JEWEL_MASK | + NFC_PROTO_MIFARE_MASK | + NFC_PROTO_FELICA_MASK | + NFC_PROTO_ISO14443_MASK | + NFC_PROTO_NFC_DEP_MASK; + + info->shdlc = nfc_shdlc_allocate(&pn544_shdlc_ops, + &init_data, protocols, + PN544_CMDS_HEADROOM, 0, + PN544_HCI_LLC_MAX_PAYLOAD, + dev_name(&client->dev)); + if (!info->shdlc) { + dev_err(&client->dev, "Cannot allocate nfc shdlc.\n"); + r = -ENOMEM; + goto err_allocshdlc; + } + + nfc_shdlc_set_clientdata(info->shdlc, info); + + return 0; + +err_allocshdlc: + free_irq(client->irq, info); + +err_rti: + if (pdata->free_resources != NULL) + pdata->free_resources(); + +err_pdata: + kfree(info); + +err_info_alloc: + return r; +} + +static __devexit int pn544_hci_remove(struct i2c_client *client) +{ + struct pn544_hci_info *info = i2c_get_clientdata(client); + struct pn544_nfc_platform_data *pdata = client->dev.platform_data; + + dev_dbg(&client->dev, "%s\n", __func__); + + nfc_shdlc_free(info->shdlc); + + if (info->state != PN544_ST_COLD) { + if (pdata->disable) + pdata->disable(); + } + + free_irq(client->irq, info); + if (pdata->free_resources) + pdata->free_resources(); + + kfree(info); + + return 0; +} + +static struct i2c_driver pn544_hci_driver = { + .driver = { + .name = PN544_HCI_DRIVER_NAME, + }, + .probe = pn544_hci_probe, + .id_table = pn544_hci_id_table, + .remove = __devexit_p(pn544_hci_remove), +}; + +static int __init pn544_hci_init(void) +{ + int r; + + pr_debug(DRIVER_DESC ": %s\n", __func__); + + r = i2c_add_driver(&pn544_hci_driver); + if (r) { + pr_err(PN544_HCI_DRIVER_NAME ": driver registration failed\n"); + return r; + } + + return 0; +} + +static void __exit pn544_hci_exit(void) +{ + i2c_del_driver(&pn544_hci_driver); +} + +module_init(pn544_hci_init); +module_exit(pn544_hci_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/include/linux/nfc/pn544.h b/include/linux/nfc/pn544.h index 7ab8521f2347..9890bbaf4328 100644 --- a/include/linux/nfc/pn544.h +++ b/include/linux/nfc/pn544.h @@ -84,6 +84,12 @@ struct pn544_fw_packet { }; #ifdef __KERNEL__ +enum { + NFC_GPIO_ENABLE, + NFC_GPIO_FW_RESET, + NFC_GPIO_IRQ +}; + /* board config */ struct pn544_nfc_platform_data { int (*request_resources) (struct i2c_client *client); @@ -91,6 +97,7 @@ struct pn544_nfc_platform_data { void (*enable) (int fw); int (*test) (void); void (*disable) (void); + int (*get_gpio)(int type); }; #endif /* __KERNEL__ */ -- cgit From 5a20ef3db28faa42dd5dc86ad75d2736bcd3da4c Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 29 Apr 2012 02:04:06 +0200 Subject: ssb: remove rev from boardinfo Previously the rev contained the revision read from the pci config space and was used as board_rev in the wireless drivers. This is wrong the board_rev is only fetched from the sprom accordingly to the open source part of the Broadcom SDK and brcmsmac. This patch removes the rev from the boardinfo structure and uses the board_rev attribute from sprom instead. This attribute is filled by PCI, PCMCIA, SDIO and SoC code. Signed-off-by: Hauke Mehrtens Tested-by: Arend van Spriel Signed-off-by: John W. Linville --- arch/mips/bcm47xx/setup.c | 2 -- drivers/net/wireless/b43/bus.c | 2 +- drivers/net/wireless/b43/main.c | 4 ++-- drivers/net/wireless/b43legacy/main.c | 2 +- drivers/net/wireless/b43legacy/phy.c | 4 ++-- drivers/net/wireless/b43legacy/radio.c | 10 +++++----- drivers/ssb/pci.c | 1 - include/linux/ssb/ssb.h | 1 - 8 files changed, 11 insertions(+), 15 deletions(-) (limited to 'include/linux') diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c index 19780aa91708..d9278a82e003 100644 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -115,8 +115,6 @@ static int bcm47xx_get_invariants(struct ssb_bus *bus, iv->boardinfo.vendor = SSB_BOARDVENDOR_BCM; if (nvram_getenv("boardtype", buf, sizeof(buf)) >= 0) iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0); - if (nvram_getenv("boardrev", buf, sizeof(buf)) >= 0) - iv->boardinfo.rev = (u16)simple_strtoul(buf, NULL, 0); bcm47xx_fill_sprom(&iv->sprom, NULL); diff --git a/drivers/net/wireless/b43/bus.c b/drivers/net/wireless/b43/bus.c index 424692df239d..8f3c0a889a4e 100644 --- a/drivers/net/wireless/b43/bus.c +++ b/drivers/net/wireless/b43/bus.c @@ -210,7 +210,7 @@ struct b43_bus_dev *b43_bus_dev_ssb_init(struct ssb_device *sdev) dev->board_vendor = sdev->bus->boardinfo.vendor; dev->board_type = sdev->bus->boardinfo.type; - dev->board_rev = sdev->bus->boardinfo.rev; + dev->board_rev = sdev->bus->sprom.board_rev; dev->chip_id = sdev->bus->chip_id; dev->chip_rev = sdev->bus->chip_rev; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 617afc8211b2..5a39b226b2e3 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -5243,10 +5243,10 @@ static void b43_sprom_fixup(struct ssb_bus *bus) /* boardflags workarounds */ if (bus->boardinfo.vendor == SSB_BOARDVENDOR_DELL && - bus->chip_id == 0x4301 && bus->boardinfo.rev == 0x74) + bus->chip_id == 0x4301 && bus->sprom.board_rev == 0x74) bus->sprom.boardflags_lo |= B43_BFL_BTCOEXIST; if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE && - bus->boardinfo.type == 0x4E && bus->boardinfo.rev > 0x40) + bus->boardinfo.type == 0x4E && bus->sprom.board_rev > 0x40) bus->sprom.boardflags_lo |= B43_BFL_PACTRL; if (bus->bustype == SSB_BUSTYPE_PCI) { pdev = bus->host_pci; diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 1deafaac43e3..cd9c9bc186d9 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -3779,7 +3779,7 @@ static void b43legacy_sprom_fixup(struct ssb_bus *bus) /* boardflags workarounds */ if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE && bus->boardinfo.type == 0x4E && - bus->boardinfo.rev > 0x40) + bus->sprom.board_rev > 0x40) bus->sprom.boardflags_lo |= B43legacy_BFL_PACTRL; } diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c index 950334197f40..995c7d0c212a 100644 --- a/drivers/net/wireless/b43legacy/phy.c +++ b/drivers/net/wireless/b43legacy/phy.c @@ -408,7 +408,7 @@ static void b43legacy_phy_setupg(struct b43legacy_wldev *dev) if (is_bcm_board_vendor(dev) && (dev->dev->bus->boardinfo.type == 0x0416) && - (dev->dev->bus->boardinfo.rev == 0x0017)) + (dev->dev->bus->sprom.board_rev == 0x0017)) return; b43legacy_ilt_write(dev, 0x5001, 0x0002); @@ -424,7 +424,7 @@ static void b43legacy_phy_setupg(struct b43legacy_wldev *dev) if (is_bcm_board_vendor(dev) && (dev->dev->bus->boardinfo.type == 0x0416) && - (dev->dev->bus->boardinfo.rev == 0x0017)) + (dev->dev->bus->sprom.board_rev == 0x0017)) return; b43legacy_ilt_write(dev, 0x0401, 0x0002); diff --git a/drivers/net/wireless/b43legacy/radio.c b/drivers/net/wireless/b43legacy/radio.c index fcbafcd603cc..896177690394 100644 --- a/drivers/net/wireless/b43legacy/radio.c +++ b/drivers/net/wireless/b43legacy/radio.c @@ -1998,7 +1998,7 @@ u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev) if (phy->type == B43legacy_PHYTYPE_G) { if (is_bcm_board_vendor(dev) && dev->dev->bus->boardinfo.type == 0x421 && - dev->dev->bus->boardinfo.rev >= 30) + dev->dev->bus->sprom.board_rev >= 30) att = 3; else if (is_bcm_board_vendor(dev) && dev->dev->bus->boardinfo.type == 0x416) @@ -2008,7 +2008,7 @@ u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev) } else { if (is_bcm_board_vendor(dev) && dev->dev->bus->boardinfo.type == 0x421 && - dev->dev->bus->boardinfo.rev >= 30) + dev->dev->bus->sprom.board_rev >= 30) att = 7; else att = 6; @@ -2018,7 +2018,7 @@ u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev) if (phy->type == B43legacy_PHYTYPE_G) { if (is_bcm_board_vendor(dev) && dev->dev->bus->boardinfo.type == 0x421 && - dev->dev->bus->boardinfo.rev >= 30) + dev->dev->bus->sprom.board_rev >= 30) att = 3; else if (is_bcm_board_vendor(dev) && dev->dev->bus->boardinfo.type == @@ -2052,9 +2052,9 @@ u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev) } if (is_bcm_board_vendor(dev) && dev->dev->bus->boardinfo.type == 0x421) { - if (dev->dev->bus->boardinfo.rev < 0x43) + if (dev->dev->bus->sprom.board_rev < 0x43) att = 2; - else if (dev->dev->bus->boardinfo.rev < 0x51) + else if (dev->dev->bus->sprom.board_rev < 0x51) att = 3; } if (att == 0xFFFF) diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index ed4124469a3a..113208e0ae33 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -784,7 +784,6 @@ static void ssb_pci_get_boardinfo(struct ssb_bus *bus, { bi->vendor = bus->host_pci->subsystem_vendor; bi->type = bus->host_pci->subsystem_device; - bi->rev = bus->host_pci->revision; } int ssb_pci_get_invariants(struct ssb_bus *bus, diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h index d27683180025..bc14bd738ade 100644 --- a/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h @@ -188,7 +188,6 @@ struct ssb_sprom { struct ssb_boardinfo { u16 vendor; u16 type; - u8 rev; }; -- cgit From 0a2fcaa70ce96be6e663234072984fd2b0ffa36e Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 29 Apr 2012 02:04:08 +0200 Subject: bcma: add boardinfo struct This struct contains information about the board, the chip is running on. The struct is filled for PCIe devices and SoCs. This information is used by b43 and will be used by brcmsmac soon. Signed-off-by: Hauke Mehrtens Tested-by: Arend van Spriel Signed-off-by: John W. Linville --- arch/mips/bcm47xx/setup.c | 2 ++ arch/mips/bcm47xx/sprom.c | 12 ++++++++++++ arch/mips/include/asm/mach-bcm47xx/bcm47xx.h | 4 ++++ drivers/bcma/host_pci.c | 3 +++ drivers/net/wireless/b43/bus.c | 4 +--- include/linux/bcma/bcma.h | 7 +++++++ 6 files changed, 29 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c index 53cdb7244244..9ef46d2a5110 100644 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -190,6 +190,8 @@ static void __init bcm47xx_register_bcma(void) err = bcma_host_soc_register(&bcm47xx_bus.bcma); if (err) panic("Failed to initialize BCMA bus (err %d)", err); + + bcm47xx_fill_bcma_boardinfo(&bcm47xx_bus.bcma.bus.boardinfo, NULL); } #endif diff --git a/arch/mips/bcm47xx/sprom.c b/arch/mips/bcm47xx/sprom.c index 279991a3583b..a29d20743039 100644 --- a/arch/mips/bcm47xx/sprom.c +++ b/arch/mips/bcm47xx/sprom.c @@ -630,3 +630,15 @@ void bcm47xx_fill_ssb_boardinfo(struct ssb_boardinfo *boardinfo, nvram_read_u16(prefix, NULL, "boardtype", &boardinfo->type, 0); } #endif + +#ifdef CONFIG_BCM47XX_BCMA +void bcm47xx_fill_bcma_boardinfo(struct bcma_boardinfo *boardinfo, + const char *prefix) +{ + nvram_read_u16(prefix, NULL, "boardvendor", &boardinfo->vendor, 0); + if (!boardinfo->vendor) + boardinfo->vendor = SSB_BOARDVENDOR_BCM; + + nvram_read_u16(prefix, NULL, "boardtype", &boardinfo->type, 0); +} +#endif diff --git a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h index 42887c66ade2..26fdaf40b930 100644 --- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h +++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h @@ -51,5 +51,9 @@ void bcm47xx_fill_sprom_ethernet(struct ssb_sprom *sprom, const char *prefix); void bcm47xx_fill_ssb_boardinfo(struct ssb_boardinfo *boardinfo, const char *prefix); #endif +#ifdef CONFIG_BCM47XX_BCMA +void bcm47xx_fill_bcma_boardinfo(struct bcma_boardinfo *boardinfo, + const char *prefix); +#endif #endif /* __ASM_BCM47XX_H */ diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c index e3928d68802b..3a93563b4f7a 100644 --- a/drivers/bcma/host_pci.c +++ b/drivers/bcma/host_pci.c @@ -201,6 +201,9 @@ static int __devinit bcma_host_pci_probe(struct pci_dev *dev, bus->hosttype = BCMA_HOSTTYPE_PCI; bus->ops = &bcma_host_pci_ops; + bus->boardinfo.vendor = bus->host_pci->subsystem_vendor; + bus->boardinfo.type = bus->host_pci->subsystem_device; + /* Register */ err = bcma_bus_register(bus); if (err) diff --git a/drivers/net/wireless/b43/bus.c b/drivers/net/wireless/b43/bus.c index 8f3c0a889a4e..565fdbdd6915 100644 --- a/drivers/net/wireless/b43/bus.c +++ b/drivers/net/wireless/b43/bus.c @@ -107,11 +107,9 @@ struct b43_bus_dev *b43_bus_dev_bcma_init(struct bcma_device *core) dev->dma_dev = core->dma_dev; dev->irq = core->irq; - /* dev->board_vendor = core->bus->boardinfo.vendor; dev->board_type = core->bus->boardinfo.type; - dev->board_rev = core->bus->boardinfo.rev; - */ + dev->board_rev = core->bus->sprom.board_rev; dev->chip_id = core->bus->chipinfo.id; dev->chip_rev = core->bus->chipinfo.rev; diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h index 5af9a075498f..747f2ca6f04e 100644 --- a/include/linux/bcma/bcma.h +++ b/include/linux/bcma/bcma.h @@ -26,6 +26,11 @@ struct bcma_chipinfo { u8 pkg; }; +struct bcma_boardinfo { + u16 vendor; + u16 type; +}; + enum bcma_clkmode { BCMA_CLKMODE_FAST, BCMA_CLKMODE_DYNAMIC, @@ -198,6 +203,8 @@ struct bcma_bus { struct bcma_chipinfo chipinfo; + struct bcma_boardinfo boardinfo; + struct bcma_device *mapped_core; struct list_head cores; u8 nr_cores; -- cgit From bf7d420b4a3ea06d9638ec7f1b9d7971fa7f4f66 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 29 Apr 2012 02:04:10 +0200 Subject: ssb/bcma: fill attribute alpha2 from sprom The attribute country_code and alpha2 are two different attributes in the sprom. country_code contains some code in an 8 bit coding and alpha2 contains two chars with the country code. The attributes where read out wrongly in the past and country_code is only available on sprom version 1. Signed-off-by: Hauke Mehrtens Tested-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/bcma/sprom.c | 3 ++- drivers/ssb/pci.c | 16 +++++++++++----- include/linux/ssb/ssb_regs.h | 1 + 3 files changed, 14 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c index 3e2a6002aae6..1799372131d2 100644 --- a/drivers/bcma/sprom.c +++ b/drivers/bcma/sprom.c @@ -243,7 +243,8 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom) SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, ~0, 0); SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, ~0, 0); - SPEX(country_code, SSB_SPROM8_CCODE, ~0, 0); + SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8); + SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0); /* Extract cores power info info */ for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) { diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index 113208e0ae33..82589d447f85 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -360,8 +360,9 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in) SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14); SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15); SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0); - SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE, - SSB_SPROM1_BINF_CCODE_SHIFT); + if (out->revision == 1) + SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE, + SSB_SPROM1_BINF_CCODE_SHIFT); SPEX(ant_available_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA, SSB_SPROM1_BINF_ANTA_SHIFT); SPEX(ant_available_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG, @@ -387,6 +388,8 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in) SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0); if (out->revision >= 2) SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0); + SPEX(alpha2[0], SSB_SPROM1_CCODE, 0xff00, 8); + SPEX(alpha2[1], SSB_SPROM1_CCODE, 0x00ff, 0); /* Extract the antenna gain values. */ out->antenna_gain.a0 = r123_extract_antgain(out->revision, in, @@ -456,13 +459,15 @@ static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in) SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A, SSB_SPROM4_ETHPHY_ET1A_SHIFT); if (out->revision == 4) { - SPEX(country_code, SSB_SPROM4_CCODE, 0xFFFF, 0); + SPEX(alpha2[0], SSB_SPROM4_CCODE, 0xff00, 8); + SPEX(alpha2[1], SSB_SPROM4_CCODE, 0x00ff, 0); SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0); SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0); SPEX(boardflags2_lo, SSB_SPROM4_BFL2LO, 0xFFFF, 0); SPEX(boardflags2_hi, SSB_SPROM4_BFL2HI, 0xFFFF, 0); } else { - SPEX(country_code, SSB_SPROM5_CCODE, 0xFFFF, 0); + SPEX(alpha2[0], SSB_SPROM5_CCODE, 0xff00, 8); + SPEX(alpha2[1], SSB_SPROM5_CCODE, 0x00ff, 0); SPEX(boardflags_lo, SSB_SPROM5_BFLLO, 0xFFFF, 0); SPEX(boardflags_hi, SSB_SPROM5_BFLHI, 0xFFFF, 0); SPEX(boardflags2_lo, SSB_SPROM5_BFL2LO, 0xFFFF, 0); @@ -525,7 +530,8 @@ static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in) v = in[SPOFF(SSB_SPROM8_IL0MAC) + i]; *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v); } - SPEX(country_code, SSB_SPROM8_CCODE, 0xFFFF, 0); + SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8); + SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0); SPEX(boardflags_lo, SSB_SPROM8_BFLLO, 0xFFFF, 0); SPEX(boardflags_hi, SSB_SPROM8_BFLHI, 0xFFFF, 0); SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, 0xFFFF, 0); diff --git a/include/linux/ssb/ssb_regs.h b/include/linux/ssb/ssb_regs.h index 40b1ef8595ee..d33bd8fec445 100644 --- a/include/linux/ssb/ssb_regs.h +++ b/include/linux/ssb/ssb_regs.h @@ -228,6 +228,7 @@ #define SSB_SPROM1_AGAIN_BG_SHIFT 0 #define SSB_SPROM1_AGAIN_A 0xFF00 /* A-PHY */ #define SSB_SPROM1_AGAIN_A_SHIFT 8 +#define SSB_SPROM1_CCODE 0x0076 /* SPROM Revision 2 (inherits from rev 1) */ #define SSB_SPROM2_BFLHI 0x0038 /* Boardflags (high 16 bits) */ -- cgit From 673335c8f0c24912d57abf9b8cd10c9d91ff1a40 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 29 Apr 2012 02:04:11 +0200 Subject: ssb: fill board_rev attribute from sprom This attribute is now used in b43 driver and should be filled for all sprom versions. Signed-off-by: Hauke Mehrtens Signed-off-by: John W. Linville --- drivers/ssb/pci.c | 2 ++ include/linux/ssb/ssb_regs.h | 1 + 2 files changed, 3 insertions(+) (limited to 'include/linux') diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index 82589d447f85..2cb604d142f4 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -458,6 +458,7 @@ static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in) SPEX(et0phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET0A, 0); SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A, SSB_SPROM4_ETHPHY_ET1A_SHIFT); + SPEX(board_rev, SSB_SPROM4_BOARDREV, 0xFFFF, 0); if (out->revision == 4) { SPEX(alpha2[0], SSB_SPROM4_CCODE, 0xff00, 8); SPEX(alpha2[1], SSB_SPROM4_CCODE, 0x00ff, 0); @@ -530,6 +531,7 @@ static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in) v = in[SPOFF(SSB_SPROM8_IL0MAC) + i]; *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v); } + SPEX(board_rev, SSB_SPROM8_BOARDREV, 0xFFFF, 0); SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8); SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0); SPEX(boardflags_lo, SSB_SPROM8_BFLLO, 0xFFFF, 0); diff --git a/include/linux/ssb/ssb_regs.h b/include/linux/ssb/ssb_regs.h index d33bd8fec445..543795f30f75 100644 --- a/include/linux/ssb/ssb_regs.h +++ b/include/linux/ssb/ssb_regs.h @@ -268,6 +268,7 @@ #define SSB_SPROM3_OFDMGPO 0x107A /* G-PHY OFDM Power Offset (4 bytes, BigEndian) */ /* SPROM Revision 4 */ +#define SSB_SPROM4_BOARDREV 0x0042 /* Board revision */ #define SSB_SPROM4_BFLLO 0x0044 /* Boardflags (low 16 bits) */ #define SSB_SPROM4_BFLHI 0x0046 /* Board Flags Hi */ #define SSB_SPROM4_BFL2LO 0x0048 /* Board flags 2 (low 16 bits) */ -- cgit From e2da4bd3ec7842fbef2bc7bffde3e1ad0c15f516 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 29 Apr 2012 02:04:13 +0200 Subject: bcma/ssb: parse new attributes from sprom These newly added attributes are used by brcmsmac. Now bcma should parse all attributes used by brcmsmac out of the sprom. Signed-off-by: Hauke Mehrtens Tested-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/bcma/sprom.c | 70 ++++++++++++++++++++++++++++++++++++++++++++ drivers/ssb/pci.c | 69 +++++++++++++++++++++++++++++++++++++++++++ include/linux/ssb/ssb_regs.h | 59 ++++++++++++++++++++++++++++++++++--- 3 files changed, 194 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c index 22c99683a180..c7f93359acb0 100644 --- a/drivers/bcma/sprom.c +++ b/drivers/bcma/sprom.c @@ -185,6 +185,18 @@ static int bcma_sprom_valid(const u16 *sprom) bus->sprom._field = ((((u32)sprom[SPOFF((_offset)+2)] << 16 | \ sprom[SPOFF(_offset)]) & (_mask)) >> (_shift)) +#define SPEX_ARRAY8(_field, _offset, _mask, _shift) \ + do { \ + SPEX(_field[0], _offset + 0, _mask, _shift); \ + SPEX(_field[1], _offset + 2, _mask, _shift); \ + SPEX(_field[2], _offset + 4, _mask, _shift); \ + SPEX(_field[3], _offset + 6, _mask, _shift); \ + SPEX(_field[4], _offset + 8, _mask, _shift); \ + SPEX(_field[5], _offset + 10, _mask, _shift); \ + SPEX(_field[6], _offset + 12, _mask, _shift); \ + SPEX(_field[7], _offset + 14, _mask, _shift); \ + } while (0) + static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom) { u16 v, o; @@ -375,6 +387,64 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom) SSB_SPROM8_AGAIN2, SSB_SPROM8_AGAIN2_SHIFT); SPEX(antenna_gain.a3, SSB_SPROM8_AGAIN23, SSB_SPROM8_AGAIN3, SSB_SPROM8_AGAIN3_SHIFT); + + SPEX(leddc_on_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_ON, + SSB_SPROM8_LEDDC_ON_SHIFT); + SPEX(leddc_off_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_OFF, + SSB_SPROM8_LEDDC_OFF_SHIFT); + + SPEX(txchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_TXCHAIN, + SSB_SPROM8_TXRXC_TXCHAIN_SHIFT); + SPEX(rxchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_RXCHAIN, + SSB_SPROM8_TXRXC_RXCHAIN_SHIFT); + SPEX(antswitch, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_SWITCH, + SSB_SPROM8_TXRXC_SWITCH_SHIFT); + + SPEX(opo, SSB_SPROM8_OFDM2GPO, 0x00ff, 0); + + SPEX_ARRAY8(mcs2gpo, SSB_SPROM8_2G_MCSPO, ~0, 0); + SPEX_ARRAY8(mcs5gpo, SSB_SPROM8_5G_MCSPO, ~0, 0); + SPEX_ARRAY8(mcs5glpo, SSB_SPROM8_5GL_MCSPO, ~0, 0); + SPEX_ARRAY8(mcs5ghpo, SSB_SPROM8_5GH_MCSPO, ~0, 0); + + SPEX(rawtempsense, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_RAWTEMP, + SSB_SPROM8_RAWTS_RAWTEMP_SHIFT); + SPEX(measpower, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_MEASPOWER, + SSB_SPROM8_RAWTS_MEASPOWER_SHIFT); + SPEX(tempsense_slope, SSB_SPROM8_OPT_CORRX, + SSB_SPROM8_OPT_CORRX_TEMP_SLOPE, + SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT); + SPEX(tempcorrx, SSB_SPROM8_OPT_CORRX, SSB_SPROM8_OPT_CORRX_TEMPCORRX, + SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT); + SPEX(tempsense_option, SSB_SPROM8_OPT_CORRX, + SSB_SPROM8_OPT_CORRX_TEMP_OPTION, + SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT); + SPEX(freqoffset_corr, SSB_SPROM8_HWIQ_IQSWP, + SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR, + SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT); + SPEX(iqcal_swp_dis, SSB_SPROM8_HWIQ_IQSWP, + SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP, + SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT); + SPEX(hw_iqcal_en, SSB_SPROM8_HWIQ_IQSWP, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL, + SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT); + + SPEX(bw40po, SSB_SPROM8_BW40PO, ~0, 0); + SPEX(cddpo, SSB_SPROM8_CDDPO, ~0, 0); + SPEX(stbcpo, SSB_SPROM8_STBCPO, ~0, 0); + SPEX(bwduppo, SSB_SPROM8_BWDUPPO, ~0, 0); + + SPEX(tempthresh, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_TRESH, + SSB_SPROM8_THERMAL_TRESH_SHIFT); + SPEX(tempoffset, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_OFFSET, + SSB_SPROM8_THERMAL_OFFSET_SHIFT); + SPEX(phycal_tempdelta, SSB_SPROM8_TEMPDELTA, + SSB_SPROM8_TEMPDELTA_PHYCAL, + SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT); + SPEX(temps_period, SSB_SPROM8_TEMPDELTA, SSB_SPROM8_TEMPDELTA_PERIOD, + SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT); + SPEX(temps_hysteresis, SSB_SPROM8_TEMPDELTA, + SSB_SPROM8_TEMPDELTA_HYSTERESIS, + SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT); } /* diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index 2cb604d142f4..e9d94968f394 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -178,6 +178,18 @@ err_pci: #define SPEX(_outvar, _offset, _mask, _shift) \ SPEX16(_outvar, _offset, _mask, _shift) +#define SPEX_ARRAY8(_field, _offset, _mask, _shift) \ + do { \ + SPEX(_field[0], _offset + 0, _mask, _shift); \ + SPEX(_field[1], _offset + 2, _mask, _shift); \ + SPEX(_field[2], _offset + 4, _mask, _shift); \ + SPEX(_field[3], _offset + 6, _mask, _shift); \ + SPEX(_field[4], _offset + 8, _mask, _shift); \ + SPEX(_field[5], _offset + 10, _mask, _shift); \ + SPEX(_field[6], _offset + 12, _mask, _shift); \ + SPEX(_field[7], _offset + 14, _mask, _shift); \ + } while (0) + static inline u8 ssb_crc8(u8 crc, u8 data) { @@ -663,6 +675,63 @@ static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in) SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT); + SPEX(leddc_on_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_ON, + SSB_SPROM8_LEDDC_ON_SHIFT); + SPEX(leddc_off_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_OFF, + SSB_SPROM8_LEDDC_OFF_SHIFT); + + SPEX(txchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_TXCHAIN, + SSB_SPROM8_TXRXC_TXCHAIN_SHIFT); + SPEX(rxchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_RXCHAIN, + SSB_SPROM8_TXRXC_RXCHAIN_SHIFT); + SPEX(antswitch, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_SWITCH, + SSB_SPROM8_TXRXC_SWITCH_SHIFT); + + SPEX(opo, SSB_SPROM8_OFDM2GPO, 0x00ff, 0); + + SPEX_ARRAY8(mcs2gpo, SSB_SPROM8_2G_MCSPO, ~0, 0); + SPEX_ARRAY8(mcs5gpo, SSB_SPROM8_5G_MCSPO, ~0, 0); + SPEX_ARRAY8(mcs5glpo, SSB_SPROM8_5GL_MCSPO, ~0, 0); + SPEX_ARRAY8(mcs5ghpo, SSB_SPROM8_5GH_MCSPO, ~0, 0); + + SPEX(rawtempsense, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_RAWTEMP, + SSB_SPROM8_RAWTS_RAWTEMP_SHIFT); + SPEX(measpower, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_MEASPOWER, + SSB_SPROM8_RAWTS_MEASPOWER_SHIFT); + SPEX(tempsense_slope, SSB_SPROM8_OPT_CORRX, + SSB_SPROM8_OPT_CORRX_TEMP_SLOPE, + SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT); + SPEX(tempcorrx, SSB_SPROM8_OPT_CORRX, SSB_SPROM8_OPT_CORRX_TEMPCORRX, + SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT); + SPEX(tempsense_option, SSB_SPROM8_OPT_CORRX, + SSB_SPROM8_OPT_CORRX_TEMP_OPTION, + SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT); + SPEX(freqoffset_corr, SSB_SPROM8_HWIQ_IQSWP, + SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR, + SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT); + SPEX(iqcal_swp_dis, SSB_SPROM8_HWIQ_IQSWP, + SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP, + SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT); + SPEX(hw_iqcal_en, SSB_SPROM8_HWIQ_IQSWP, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL, + SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT); + + SPEX(bw40po, SSB_SPROM8_BW40PO, ~0, 0); + SPEX(cddpo, SSB_SPROM8_CDDPO, ~0, 0); + SPEX(stbcpo, SSB_SPROM8_STBCPO, ~0, 0); + SPEX(bwduppo, SSB_SPROM8_BWDUPPO, ~0, 0); + + SPEX(tempthresh, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_TRESH, + SSB_SPROM8_THERMAL_TRESH_SHIFT); + SPEX(tempoffset, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_OFFSET, + SSB_SPROM8_THERMAL_OFFSET_SHIFT); + SPEX(phycal_tempdelta, SSB_SPROM8_TEMPDELTA, + SSB_SPROM8_TEMPDELTA_PHYCAL, + SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT); + SPEX(temps_period, SSB_SPROM8_TEMPDELTA, SSB_SPROM8_TEMPDELTA_PERIOD, + SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT); + SPEX(temps_hysteresis, SSB_SPROM8_TEMPDELTA, + SSB_SPROM8_TEMPDELTA_HYSTERESIS, + SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT); sprom_extract_r458(out, in); /* TODO - get remaining rev 8 stuff needed */ diff --git a/include/linux/ssb/ssb_regs.h b/include/linux/ssb/ssb_regs.h index 543795f30f75..a0525019e1d1 100644 --- a/include/linux/ssb/ssb_regs.h +++ b/include/linux/ssb/ssb_regs.h @@ -391,6 +391,11 @@ #define SSB_SPROM8_GPIOB_P2 0x00FF /* Pin 2 */ #define SSB_SPROM8_GPIOB_P3 0xFF00 /* Pin 3 */ #define SSB_SPROM8_GPIOB_P3_SHIFT 8 +#define SSB_SPROM8_LEDDC 0x009A +#define SSB_SPROM8_LEDDC_ON 0xFF00 /* oncount */ +#define SSB_SPROM8_LEDDC_ON_SHIFT 8 +#define SSB_SPROM8_LEDDC_OFF 0x00FF /* offcount */ +#define SSB_SPROM8_LEDDC_OFF_SHIFT 0 #define SSB_SPROM8_ANTAVAIL 0x009C /* Antenna available bitfields*/ #define SSB_SPROM8_ANTAVAIL_A 0xFF00 /* A-PHY bitfield */ #define SSB_SPROM8_ANTAVAIL_A_SHIFT 8 @@ -406,6 +411,13 @@ #define SSB_SPROM8_AGAIN2_SHIFT 0 #define SSB_SPROM8_AGAIN3 0xFF00 /* Antenna 3 */ #define SSB_SPROM8_AGAIN3_SHIFT 8 +#define SSB_SPROM8_TXRXC 0x00A2 +#define SSB_SPROM8_TXRXC_TXCHAIN 0x000f +#define SSB_SPROM8_TXRXC_TXCHAIN_SHIFT 0 +#define SSB_SPROM8_TXRXC_RXCHAIN 0x00f0 +#define SSB_SPROM8_TXRXC_RXCHAIN_SHIFT 4 +#define SSB_SPROM8_TXRXC_SWITCH 0xff00 +#define SSB_SPROM8_TXRXC_SWITCH_SHIFT 8 #define SSB_SPROM8_RSSIPARM2G 0x00A4 /* RSSI params for 2GHz */ #define SSB_SPROM8_RSSISMF2G 0x000F #define SSB_SPROM8_RSSISMC2G 0x00F0 @@ -432,6 +444,7 @@ #define SSB_SPROM8_TRI5GH_SHIFT 8 #define SSB_SPROM8_RXPO 0x00AC /* RX power offsets */ #define SSB_SPROM8_RXPO2G 0x00FF /* 2GHz RX power offset */ +#define SSB_SPROM8_RXPO2G_SHIFT 0 #define SSB_SPROM8_RXPO5G 0xFF00 /* 5GHz RX power offset */ #define SSB_SPROM8_RXPO5G_SHIFT 8 #define SSB_SPROM8_FEM2G 0x00AE @@ -447,10 +460,38 @@ #define SSB_SROM8_FEM_ANTSWLUT 0xF800 #define SSB_SROM8_FEM_ANTSWLUT_SHIFT 11 #define SSB_SPROM8_THERMAL 0x00B2 -#define SSB_SPROM8_MPWR_RAWTS 0x00B4 -#define SSB_SPROM8_TS_SLP_OPT_CORRX 0x00B6 -#define SSB_SPROM8_FOC_HWIQ_IQSWP 0x00B8 -#define SSB_SPROM8_PHYCAL_TEMPDELTA 0x00BA +#define SSB_SPROM8_THERMAL_OFFSET 0x00ff +#define SSB_SPROM8_THERMAL_OFFSET_SHIFT 0 +#define SSB_SPROM8_THERMAL_TRESH 0xff00 +#define SSB_SPROM8_THERMAL_TRESH_SHIFT 8 +/* Temp sense related entries */ +#define SSB_SPROM8_RAWTS 0x00B4 +#define SSB_SPROM8_RAWTS_RAWTEMP 0x01ff +#define SSB_SPROM8_RAWTS_RAWTEMP_SHIFT 0 +#define SSB_SPROM8_RAWTS_MEASPOWER 0xfe00 +#define SSB_SPROM8_RAWTS_MEASPOWER_SHIFT 9 +#define SSB_SPROM8_OPT_CORRX 0x00B6 +#define SSB_SPROM8_OPT_CORRX_TEMP_SLOPE 0x00ff +#define SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT 0 +#define SSB_SPROM8_OPT_CORRX_TEMPCORRX 0xfc00 +#define SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT 10 +#define SSB_SPROM8_OPT_CORRX_TEMP_OPTION 0x0300 +#define SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT 8 +/* FOC: freiquency offset correction, HWIQ: H/W IOCAL enable, IQSWP: IQ CAL swap disable */ +#define SSB_SPROM8_HWIQ_IQSWP 0x00B8 +#define SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR 0x000f +#define SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT 0 +#define SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP 0x0010 +#define SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT 4 +#define SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL 0x0020 +#define SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT 5 +#define SSB_SPROM8_TEMPDELTA 0x00BA +#define SSB_SPROM8_TEMPDELTA_PHYCAL 0x00ff +#define SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT 0 +#define SSB_SPROM8_TEMPDELTA_PERIOD 0x0f00 +#define SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT 8 +#define SSB_SPROM8_TEMPDELTA_HYSTERESIS 0xf000 +#define SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT 12 /* There are 4 blocks with power info sharing the same layout */ #define SSB_SROM8_PWR_INFO_CORE0 0x00C0 @@ -515,6 +556,16 @@ #define SSB_SPROM8_OFDM5GLPO 0x014A /* 5.2GHz OFDM power offset */ #define SSB_SPROM8_OFDM5GHPO 0x014E /* 5.8GHz OFDM power offset */ +#define SSB_SPROM8_2G_MCSPO 0x0152 +#define SSB_SPROM8_5G_MCSPO 0x0162 +#define SSB_SPROM8_5GL_MCSPO 0x0172 +#define SSB_SPROM8_5GH_MCSPO 0x0182 + +#define SSB_SPROM8_CDDPO 0x0192 +#define SSB_SPROM8_STBCPO 0x0194 +#define SSB_SPROM8_BW40PO 0x0196 +#define SSB_SPROM8_BWDUPPO 0x0198 + /* Values for boardflags_lo read from SPROM */ #define SSB_BFL_BTCOEXIST 0x0001 /* implements Bluetooth coexistance */ #define SSB_BFL_PACTRL 0x0002 /* GPIO 9 controlling the PA */ -- cgit From 29f6b3d823885093890b1604d8450e7b57a31281 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 29 Apr 2012 02:18:50 +0200 Subject: bcma: add bcma_core_pci_extend_L1timer This code is based on code from pcie_extendL1timer() in brcmsmac. This patch is part of the move of pci specific code from brcmsmac to bcma. Signed-off-by: Hauke Mehrtens Tested-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/bcma/driver_pci.c | 16 ++++++++++++++-- include/linux/bcma/bcma_driver_pci.h | 2 ++ 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/drivers/bcma/driver_pci.c b/drivers/bcma/driver_pci.c index 4d38ae179b48..949206674dc8 100644 --- a/drivers/bcma/driver_pci.c +++ b/drivers/bcma/driver_pci.c @@ -24,14 +24,12 @@ u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address) return pcicore_read32(pc, BCMA_CORE_PCI_PCIEIND_DATA); } -#if 0 static void bcma_pcie_write(struct bcma_drv_pci *pc, u32 address, u32 data) { pcicore_write32(pc, BCMA_CORE_PCI_PCIEIND_ADDR, address); pcicore_read32(pc, BCMA_CORE_PCI_PCIEIND_ADDR); pcicore_write32(pc, BCMA_CORE_PCI_PCIEIND_DATA, data); } -#endif static void bcma_pcie_mdio_set_phy(struct bcma_drv_pci *pc, u8 phy) { @@ -224,3 +222,17 @@ out: return err; } EXPORT_SYMBOL_GPL(bcma_core_pci_irq_ctl); + +void bcma_core_pci_extend_L1timer(struct bcma_drv_pci *pc, bool extend) +{ + u32 w; + + w = bcma_pcie_read(pc, BCMA_CORE_PCI_DLLP_PMTHRESHREG); + if (extend) + w |= BCMA_CORE_PCI_ASPMTIMER_EXTEND; + else + w &= ~BCMA_CORE_PCI_ASPMTIMER_EXTEND; + bcma_pcie_write(pc, BCMA_CORE_PCI_DLLP_PMTHRESHREG, w); + bcma_pcie_read(pc, BCMA_CORE_PCI_DLLP_PMTHRESHREG); +} +EXPORT_SYMBOL_GPL(bcma_core_pci_extend_L1timer); diff --git a/include/linux/bcma/bcma_driver_pci.h b/include/linux/bcma/bcma_driver_pci.h index 46c71e27d31f..20c9f96d4070 100644 --- a/include/linux/bcma/bcma_driver_pci.h +++ b/include/linux/bcma/bcma_driver_pci.h @@ -133,6 +133,7 @@ struct pci_dev; #define BCMA_CORE_PCI_DLLP_LRREG 0x120 /* Link Replay */ #define BCMA_CORE_PCI_DLLP_LACKTOREG 0x124 /* Link Ack Timeout */ #define BCMA_CORE_PCI_DLLP_PMTHRESHREG 0x128 /* Power Management Threshold */ +#define BCMA_CORE_PCI_ASPMTIMER_EXTEND 0x01000000 /* > rev7: enable extend ASPM timer */ #define BCMA_CORE_PCI_DLLP_RTRYWPREG 0x12C /* Retry buffer write ptr */ #define BCMA_CORE_PCI_DLLP_RTRYRPREG 0x130 /* Retry buffer Read ptr */ #define BCMA_CORE_PCI_DLLP_RTRYPPREG 0x134 /* Retry buffer Purged ptr */ @@ -207,6 +208,7 @@ struct bcma_drv_pci { extern void __devinit bcma_core_pci_init(struct bcma_drv_pci *pc); extern int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core, bool enable); +extern void bcma_core_pci_extend_L1timer(struct bcma_drv_pci *pc, bool extend); extern int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev); extern int bcma_core_pci_plat_dev_init(struct pci_dev *dev); -- cgit From ec00f3732129e57206e9ef9883d681ad6584f5dd Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 29 Apr 2012 02:18:51 +0200 Subject: bcma: add bcma_core_pci_fixcfg() This code is based on code from pcicore_fixcfg() in brcmsmac. This patch is part of the move of pci specific code from brcmsmac to bcma. Signed-off-by: Hauke Mehrtens Tested-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/bcma/driver_pci.c | 19 +++++++++++++++++++ include/linux/bcma/bcma_driver_pci.h | 5 +++++ 2 files changed, 24 insertions(+) (limited to 'include/linux') diff --git a/drivers/bcma/driver_pci.c b/drivers/bcma/driver_pci.c index 949206674dc8..472d14fad643 100644 --- a/drivers/bcma/driver_pci.c +++ b/drivers/bcma/driver_pci.c @@ -168,12 +168,31 @@ static void bcma_pcicore_serdes_workaround(struct bcma_drv_pci *pc) tmp & ~BCMA_CORE_PCI_PLL_CTRL_FREQDET_EN); } +static void bcma_core_pci_fixcfg(struct bcma_drv_pci *pc) +{ + struct bcma_device *core = pc->core; + u16 val16, core_index; + uint regoff; + + regoff = BCMA_CORE_PCI_SPROM(BCMA_CORE_PCI_SPROM_PI_OFFSET); + core_index = (u16)core->core_index; + + val16 = pcicore_read16(pc, regoff); + if (((val16 & BCMA_CORE_PCI_SPROM_PI_MASK) >> BCMA_CORE_PCI_SPROM_PI_SHIFT) + != core_index) { + val16 = (core_index << BCMA_CORE_PCI_SPROM_PI_SHIFT) | + (val16 & ~BCMA_CORE_PCI_SPROM_PI_MASK); + pcicore_write16(pc, regoff, val16); + } +} + /************************************************** * Init. **************************************************/ static void __devinit bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc) { + bcma_core_pci_fixcfg(pc); bcma_pcicore_serdes_workaround(pc); } diff --git a/include/linux/bcma/bcma_driver_pci.h b/include/linux/bcma/bcma_driver_pci.h index 20c9f96d4070..5b0542c336ed 100644 --- a/include/linux/bcma/bcma_driver_pci.h +++ b/include/linux/bcma/bcma_driver_pci.h @@ -87,6 +87,9 @@ struct pci_dev; #define BCMA_CORE_PCI_PCICFG2 0x0600 /* PCI config space 2 (rev >= 8) */ #define BCMA_CORE_PCI_PCICFG3 0x0700 /* PCI config space 3 (rev >= 8) */ #define BCMA_CORE_PCI_SPROM(wordoffset) (0x0800 + ((wordoffset) * 2)) /* SPROM shadow area (72 bytes) */ +#define BCMA_CORE_PCI_SPROM_PI_OFFSET 0 /* first word */ +#define BCMA_CORE_PCI_SPROM_PI_MASK 0xf000 /* bit 15:12 */ +#define BCMA_CORE_PCI_SPROM_PI_SHIFT 12 /* bit 15:12 */ /* SBtoPCIx */ #define BCMA_CORE_PCI_SBTOPCI_MEM 0x00000000 @@ -202,7 +205,9 @@ struct bcma_drv_pci { }; /* Register access */ +#define pcicore_read16(pc, offset) bcma_read16((pc)->core, offset) #define pcicore_read32(pc, offset) bcma_read32((pc)->core, offset) +#define pcicore_write16(pc, offset, val) bcma_write16((pc)->core, offset, val) #define pcicore_write32(pc, offset, val) bcma_write32((pc)->core, offset, val) extern void __devinit bcma_core_pci_init(struct bcma_drv_pci *pc); -- cgit From 2b2715b83c433d22b10bd654e102baea6f5589b0 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 29 Apr 2012 02:18:52 +0200 Subject: bcma: add bcma_core_pci_config_fixup() This code is based on code from pcie_misc_config_fixup() in brcmsmac. This patch is part of the move of pci specific code from brcmsmac to bcma. Signed-off-by: Hauke Mehrtens Tested-by: Arend van Spriel Signed-off-by: John W. Linville --- drivers/bcma/driver_pci.c | 18 ++++++++++++++++++ include/linux/bcma/bcma_driver_pci.h | 4 ++++ 2 files changed, 22 insertions(+) (limited to 'include/linux') diff --git a/drivers/bcma/driver_pci.c b/drivers/bcma/driver_pci.c index 472d14fad643..9a96f14c8f47 100644 --- a/drivers/bcma/driver_pci.c +++ b/drivers/bcma/driver_pci.c @@ -186,6 +186,23 @@ static void bcma_core_pci_fixcfg(struct bcma_drv_pci *pc) } } +/* Fix MISC config to allow coming out of L2/L3-Ready state w/o PRST */ +/* Needs to happen when coming out of 'standby'/'hibernate' */ +static void bcma_core_pci_config_fixup(struct bcma_drv_pci *pc) +{ + u16 val16; + uint regoff; + + regoff = BCMA_CORE_PCI_SPROM(BCMA_CORE_PCI_SPROM_MISC_CONFIG); + + val16 = pcicore_read16(pc, regoff); + + if (!(val16 & BCMA_CORE_PCI_SPROM_L23READY_EXIT_NOPERST)) { + val16 |= BCMA_CORE_PCI_SPROM_L23READY_EXIT_NOPERST; + pcicore_write16(pc, regoff, val16); + } +} + /************************************************** * Init. **************************************************/ @@ -194,6 +211,7 @@ static void __devinit bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc) { bcma_core_pci_fixcfg(pc); bcma_pcicore_serdes_workaround(pc); + bcma_core_pci_config_fixup(pc); } void __devinit bcma_core_pci_init(struct bcma_drv_pci *pc) diff --git a/include/linux/bcma/bcma_driver_pci.h b/include/linux/bcma/bcma_driver_pci.h index 5b0542c336ed..41da581e1612 100644 --- a/include/linux/bcma/bcma_driver_pci.h +++ b/include/linux/bcma/bcma_driver_pci.h @@ -90,6 +90,10 @@ struct pci_dev; #define BCMA_CORE_PCI_SPROM_PI_OFFSET 0 /* first word */ #define BCMA_CORE_PCI_SPROM_PI_MASK 0xf000 /* bit 15:12 */ #define BCMA_CORE_PCI_SPROM_PI_SHIFT 12 /* bit 15:12 */ +#define BCMA_CORE_PCI_SPROM_MISC_CONFIG 5 /* word 5 */ +#define BCMA_CORE_PCI_SPROM_L23READY_EXIT_NOPERST 0x8000 /* bit 15 */ +#define BCMA_CORE_PCI_SPROM_CLKREQ_OFFSET_REV5 20 /* word 20 for srom rev <= 5 */ +#define BCMA_CORE_PCI_SPROM_CLKREQ_ENB 0x0800 /* bit 11 */ /* SBtoPCIx */ #define BCMA_CORE_PCI_SBTOPCI_MEM 0x00000000 -- cgit From dbd4fcaf8d664fab4163b1f8682e41ad8bff3444 Mon Sep 17 00:00:00 2001 From: Samuel Ortiz Date: Thu, 10 May 2012 19:45:51 +0200 Subject: NFC: Export nfc.h to userland The netlink commands and attributes, along with the socket structure definitions need to be exported. Signed-off-by: Samuel Ortiz Signed-off-by: John W. Linville --- include/linux/Kbuild | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 3c9b616c834a..f08e3aec1113 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -271,6 +271,7 @@ header-y += netfilter_ipv4.h header-y += netfilter_ipv6.h header-y += netlink.h header-y += netrom.h +header-y += nfc.h header-y += nfs.h header-y += nfs2.h header-y += nfs3.h -- cgit From 3383b5a69de59eeef2501834c6e0960b7e2bff28 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 10 May 2012 20:14:43 +0200 Subject: nl80211: prevent additions to old station flags API We don't really want/need to maintain the old station flags API any more, so refuse changes to new (not yet defined) flags from the old flags API. Signed-off-by: Johannes Berg Signed-off-by: John W. Linville --- include/linux/nl80211.h | 2 ++ net/wireless/nl80211.c | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index f296a64d103b..a6959f72745e 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -1594,6 +1594,8 @@ enum nl80211_sta_flags { NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1 }; +#define NL80211_STA_FLAG_MAX_OLD_API NL80211_STA_FLAG_TDLS_PEER + /** * struct nl80211_sta_flag_update - station flags mask/set * @mask: mask of station flags to set diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b67b1114e25a..f1b0774d098b 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -2410,10 +2410,16 @@ static int parse_station_flags(struct genl_info *info, return -EINVAL; } - for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++) - if (flags[flag]) + for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++) { + if (flags[flag]) { params->sta_flags_set |= (1< NL80211_STA_FLAG_MAX_OLD_API) + return -EINVAL; + } + } + return 0; } -- cgit From 35c579070a349cfe54f9e09a47df2c5b68d58469 Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Mon, 21 May 2012 14:20:08 +0000 Subject: phy/micrel: Fix ID of KSZ9021 Right ID of KSZ9021 is 0x00221610. Because lower 4bit is a revision number, it varies according to a chip. Signed-off-by: Nobuhiro Iwamatsu Cc: David J. Choi Signed-off-by: David S. Miller --- include/linux/micrel_phy.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/micrel_phy.h b/include/linux/micrel_phy.h index dd8da342a991..61f0905bdc48 100644 --- a/include/linux/micrel_phy.h +++ b/include/linux/micrel_phy.h @@ -3,7 +3,7 @@ #define MICREL_PHY_ID_MASK 0x00fffff0 -#define PHY_ID_KSZ9021 0x00221611 +#define PHY_ID_KSZ9021 0x00221610 #define PHY_ID_KS8737 0x00221720 #define PHY_ID_KS8041 0x00221510 #define PHY_ID_KS8051 0x00221550 -- cgit From 37c106d0a444bcb48648ed1366890333972e5990 Mon Sep 17 00:00:00 2001 From: stephen hemminger Date: Tue, 22 May 2012 11:01:05 +0000 Subject: if: restore token ring ARP type to header Recent removal of Token Ring breaks the build of iproute2. Even though Token Ring support is gone from the kernel, it is worth keeping the the definition of the TR ARP type to avoid breaking userspace programs that use this file. Signed-off-by: Stephen Hemminger Signed-off-by: David S. Miller --- include/linux/if_arp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h index 26cb3c2c5c71..f0e69c6e8208 100644 --- a/include/linux/if_arp.h +++ b/include/linux/if_arp.h @@ -82,7 +82,7 @@ #define ARPHRD_FCPL 786 /* Fibrechannel public loop */ #define ARPHRD_FCFABRIC 787 /* Fibrechannel fabric */ /* 787->799 reserved for fibrechannel media types */ -/* 800 used to be used for token ring */ +#define ARPHRD_IEEE802_TR 800 /* Magic type ident for TR */ #define ARPHRD_IEEE80211 801 /* IEEE 802.11 */ #define ARPHRD_IEEE80211_PRISM 802 /* IEEE 802.11 + Prism2 header */ #define ARPHRD_IEEE80211_RADIOTAP 803 /* IEEE 802.11 + radiotap header */ -- cgit From d0a24a3516fb36023bef28d2355fa34e7f32029f Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Wed, 23 May 2012 04:43:45 +0000 Subject: ipx: restore token ring define to include/linux/ipx.h Commit 211ed865108e24697b44bee5daac502ee6bdd4a4 "net: delete all instances of special processing for token ring" removed the define for IPX_FRAME_TR_8022. While it is unlikely, we can't be 100% sure that there aren't random userspace consumers of this value, so restore it. The only instance I could find was in ncpfs-2.2.6, and it was safe as-is, since it used #ifdef IPX_FRAME_TR_8022 around the two use cases it had, but there may be other userspace packages without similar ifdefs. Cc: Stephen Hemminger Signed-off-by: Paul Gortmaker Signed-off-by: David S. Miller --- include/linux/ipx.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/ipx.h b/include/linux/ipx.h index 8f0243982eb6..3d48014cdd71 100644 --- a/include/linux/ipx.h +++ b/include/linux/ipx.h @@ -38,7 +38,7 @@ struct ipx_interface_definition { #define IPX_FRAME_8022 2 #define IPX_FRAME_ETHERII 3 #define IPX_FRAME_8023 4 -/* obsolete token ring was 5 */ +#define IPX_FRAME_TR_8022 5 /* obsolete */ unsigned char ipx_special; #define IPX_SPECIAL_NONE 0 #define IPX_PRIMARY 1 -- cgit From 31fe62b9586643953f0c0c37a6357dafc69034e2 Mon Sep 17 00:00:00 2001 From: Tim Bird Date: Wed, 23 May 2012 13:33:35 +0000 Subject: mm: add a low limit to alloc_large_system_hash UDP stack needs a minimum hash size value for proper operation and also uses alloc_large_system_hash() for proper NUMA distribution of its hash tables and automatic sizing depending on available system memory. On some low memory situations, udp_table_init() must ignore the alloc_large_system_hash() result and reallocs a bigger memory area. As we cannot easily free old hash table, we leak it and kmemleak can issue a warning. This patch adds a low limit parameter to alloc_large_system_hash() to solve this problem. We then specify UDP_HTABLE_SIZE_MIN for UDP/UDPLite hash table allocation. Reported-by: Mark Asselstine Reported-by: Tim Bird Signed-off-by: Eric Dumazet Cc: Paul Gortmaker Signed-off-by: David S. Miller --- fs/dcache.c | 2 ++ fs/inode.c | 2 ++ include/linux/bootmem.h | 3 ++- kernel/pid.c | 3 ++- mm/page_alloc.c | 7 +++++-- net/ipv4/route.c | 1 + net/ipv4/tcp.c | 2 ++ net/ipv4/udp.c | 30 ++++++++++-------------------- 8 files changed, 26 insertions(+), 24 deletions(-) (limited to 'include/linux') diff --git a/fs/dcache.c b/fs/dcache.c index 8c1ab8fb5012..4435d8b32904 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -3093,6 +3093,7 @@ static void __init dcache_init_early(void) HASH_EARLY, &d_hash_shift, &d_hash_mask, + 0, 0); for (loop = 0; loop < (1U << d_hash_shift); loop++) @@ -3123,6 +3124,7 @@ static void __init dcache_init(void) 0, &d_hash_shift, &d_hash_mask, + 0, 0); for (loop = 0; loop < (1U << d_hash_shift); loop++) diff --git a/fs/inode.c b/fs/inode.c index 9f4f5fecc096..e3ef2573cbdf 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1647,6 +1647,7 @@ void __init inode_init_early(void) HASH_EARLY, &i_hash_shift, &i_hash_mask, + 0, 0); for (loop = 0; loop < (1U << i_hash_shift); loop++) @@ -1677,6 +1678,7 @@ void __init inode_init(void) 0, &i_hash_shift, &i_hash_mask, + 0, 0); for (loop = 0; loop < (1U << i_hash_shift); loop++) diff --git a/include/linux/bootmem.h b/include/linux/bootmem.h index 66d3e954eb6c..1a0cd270bb7a 100644 --- a/include/linux/bootmem.h +++ b/include/linux/bootmem.h @@ -154,7 +154,8 @@ extern void *alloc_large_system_hash(const char *tablename, int flags, unsigned int *_hash_shift, unsigned int *_hash_mask, - unsigned long limit); + unsigned long low_limit, + unsigned long high_limit); #define HASH_EARLY 0x00000001 /* Allocating during early boot? */ #define HASH_SMALL 0x00000002 /* sub-page allocation allowed, min diff --git a/kernel/pid.c b/kernel/pid.c index 9f08dfabaf13..e86b291ad834 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -547,7 +547,8 @@ void __init pidhash_init(void) pid_hash = alloc_large_system_hash("PID", sizeof(*pid_hash), 0, 18, HASH_EARLY | HASH_SMALL, - &pidhash_shift, NULL, 4096); + &pidhash_shift, NULL, + 0, 4096); pidhash_size = 1U << pidhash_shift; for (i = 0; i < pidhash_size; i++) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 918330f71dba..b7af568f0ed9 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -5242,9 +5242,10 @@ void *__init alloc_large_system_hash(const char *tablename, int flags, unsigned int *_hash_shift, unsigned int *_hash_mask, - unsigned long limit) + unsigned long low_limit, + unsigned long high_limit) { - unsigned long long max = limit; + unsigned long long max = high_limit; unsigned long log2qty, size; void *table = NULL; @@ -5282,6 +5283,8 @@ void *__init alloc_large_system_hash(const char *tablename, } max = min(max, 0x80000000ULL); + if (numentries < low_limit) + numentries = low_limit; if (numentries > max) numentries = max; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index ffcb3b016843..98b30d08efe9 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -3452,6 +3452,7 @@ int __init ip_rt_init(void) 0, &rt_hash_log, &rt_hash_mask, + 0, rhash_entries ? 0 : 512 * 1024); memset(rt_hash_table, 0, (rt_hash_mask + 1) * sizeof(struct rt_hash_bucket)); rt_hash_lock_init(); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index bb485fcb077e..3ba605f60e4e 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -3514,6 +3514,7 @@ void __init tcp_init(void) 0, NULL, &tcp_hashinfo.ehash_mask, + 0, thash_entries ? 0 : 512 * 1024); for (i = 0; i <= tcp_hashinfo.ehash_mask; i++) { INIT_HLIST_NULLS_HEAD(&tcp_hashinfo.ehash[i].chain, i); @@ -3530,6 +3531,7 @@ void __init tcp_init(void) 0, &tcp_hashinfo.bhash_size, NULL, + 0, 64 * 1024); tcp_hashinfo.bhash_size = 1U << tcp_hashinfo.bhash_size; for (i = 0; i < tcp_hashinfo.bhash_size; i++) { diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 609397ee78fb..eaca73644e79 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -2192,26 +2192,16 @@ void __init udp_table_init(struct udp_table *table, const char *name) { unsigned int i; - if (!CONFIG_BASE_SMALL) - table->hash = alloc_large_system_hash(name, - 2 * sizeof(struct udp_hslot), - uhash_entries, - 21, /* one slot per 2 MB */ - 0, - &table->log, - &table->mask, - 64 * 1024); - /* - * Make sure hash table has the minimum size - */ - if (CONFIG_BASE_SMALL || table->mask < UDP_HTABLE_SIZE_MIN - 1) { - table->hash = kmalloc(UDP_HTABLE_SIZE_MIN * - 2 * sizeof(struct udp_hslot), GFP_KERNEL); - if (!table->hash) - panic(name); - table->log = ilog2(UDP_HTABLE_SIZE_MIN); - table->mask = UDP_HTABLE_SIZE_MIN - 1; - } + table->hash = alloc_large_system_hash(name, + 2 * sizeof(struct udp_hslot), + uhash_entries, + 21, /* one slot per 2 MB */ + 0, + &table->log, + &table->mask, + UDP_HTABLE_SIZE_MIN, + 64 * 1024); + table->hash2 = table->hash + (table->mask + 1); for (i = 0; i <= table->mask; i++) { INIT_HLIST_NULLS_HEAD(&table->hash[i].head, i); -- cgit