diff options
89 files changed, 833 insertions, 713 deletions
diff --git a/Documentation/rfkill.txt b/Documentation/rfkill.txt index 1b74b5f30af..c8acd8659e9 100644 --- a/Documentation/rfkill.txt +++ b/Documentation/rfkill.txt @@ -3,9 +3,8 @@ rfkill - RF kill switch support 1. Introduction 2. Implementation details -3. Kernel driver guidelines -4. Kernel API -5. Userspace support +3. Kernel API +4. Userspace support 1. Introduction @@ -19,82 +18,62 @@ disable all transmitters of a certain type (or all). This is intended for situations where transmitters need to be turned off, for example on aircraft. +The rfkill subsystem has a concept of "hard" and "soft" block, which +differ little in their meaning (block == transmitters off) but rather in +whether they can be changed or not: + - hard block: read-only radio block that cannot be overriden by software + - soft block: writable radio block (need not be readable) that is set by + the system software. 2. Implementation details -The rfkill subsystem is composed of various components: the rfkill class, the -rfkill-input module (an input layer handler), and some specific input layer -events. - -The rfkill class is provided for kernel drivers to register their radio -transmitter with the kernel, provide methods for turning it on and off and, -optionally, letting the system know about hardware-disabled states that may -be implemented on the device. This code is enabled with the CONFIG_RFKILL -Kconfig option, which drivers can "select". - -The rfkill class code also notifies userspace of state changes, this is -achieved via uevents. It also provides some sysfs files for userspace to -check the status of radio transmitters. See the "Userspace support" section -below. +The rfkill subsystem is composed of three main components: + * the rfkill core, + * the deprecated rfkill-input module (an input layer handler, being + replaced by userspace policy code) and + * the rfkill drivers. +The rfkill core provides API for kernel drivers to register their radio +transmitter with the kernel, methods for turning it on and off and, letting +the system know about hardware-disabled states that may be implemented on +the device. -The rfkill-input code implements a basic response to rfkill buttons -- it -implements turning on/off all devices of a certain class (or all). +The rfkill core code also notifies userspace of state changes, and provides +ways for userspace to query the current states. See the "Userspace support" +section below. When the device is hard-blocked (either by a call to rfkill_set_hw_state() -or from query_hw_block) set_block() will be invoked but drivers can well -ignore the method call since they can use the return value of the function -rfkill_set_hw_state() to sync the software state instead of keeping track -of calls to set_block(). - - -The entire functionality is spread over more than one subsystem: - - * The kernel input layer generates KEY_WWAN, KEY_WLAN etc. and - SW_RFKILL_ALL -- when the user presses a button. Drivers for radio - transmitters generally do not register to the input layer, unless the - device really provides an input device (i.e. a button that has no - effect other than generating a button press event) - - * The rfkill-input code hooks up to these events and switches the soft-block - of the various radio transmitters, depending on the button type. - - * The rfkill drivers turn off/on their transmitters as requested. - - * The rfkill class will generate userspace notifications (uevents) to tell - userspace what the current state is. +or from query_hw_block) set_block() will be invoked for additional software +block, but drivers can ignore the method call since they can use the return +value of the function rfkill_set_hw_state() to sync the software state +instead of keeping track of calls to set_block(). In fact, drivers should +use the return value of rfkill_set_hw_state() unless the hardware actually +keeps track of soft and hard block separately. +3. Kernel API -3. Kernel driver guidelines - -Drivers for radio transmitters normally implement only the rfkill class. -These drivers may not unblock the transmitter based on own decisions, they -should act on information provided by the rfkill class only. +Drivers for radio transmitters normally implement an rfkill driver. Platform drivers might implement input devices if the rfkill button is just that, a button. If that button influences the hardware then you need to -implement an rfkill class instead. This also applies if the platform provides +implement an rfkill driver instead. This also applies if the platform provides a way to turn on/off the transmitter(s). -During suspend/hibernation, transmitters should only be left enabled when -wake-on wlan or similar functionality requires it and the device wasn't -blocked before suspend/hibernate. Note that it may be necessary to update -the rfkill subsystem's idea of what the current state is at resume time if -the state may have changed over suspend. - +For some platforms, it is possible that the hardware state changes during +suspend/hibernation, in which case it will be necessary to update the rfkill +core with the current state is at resume time. +To create an rfkill driver, driver's Kconfig needs to have -4. Kernel API + depends on RFKILL || !RFKILL -To build a driver with rfkill subsystem support, the driver should depend on -(or select) the Kconfig symbol RFKILL. - -The hardware the driver talks to may be write-only (where the current state -of the hardware is unknown), or read-write (where the hardware can be queried -about its current state). +to ensure the driver cannot be built-in when rfkill is modular. The !RFKILL +case allows the driver to be built when rfkill is not configured, which which +case all rfkill API can still be used but will be provided by static inlines +which compile to almost nothing. Calling rfkill_set_hw_state() when a state change happens is required from rfkill drivers that control devices that can be hard-blocked unless they also @@ -105,10 +84,33 @@ device). Don't do this unless you cannot get the event in any other way. 5. Userspace support -The following sysfs entries exist for every rfkill device: +The recommended userspace interface to use is /dev/rfkill, which is a misc +character device that allows userspace to obtain and set the state of rfkill +devices and sets of devices. It also notifies userspace about device addition +and removal. The API is a simple read/write API that is defined in +linux/rfkill.h, with one ioctl that allows turning off the deprecated input +handler in the kernel for the transition period. + +Except for the one ioctl, communication with the kernel is done via read() +and write() of instances of 'struct rfkill_event'. In this structure, the +soft and hard block are properly separated (unlike sysfs, see below) and +userspace is able to get a consistent snapshot of all rfkill devices in the +system. Also, it is possible to switch all rfkill drivers (or all drivers of +a specified type) into a state which also updates the default state for +hotplugged devices. + +After an application opens /dev/rfkill, it can read the current state of +all devices, and afterwards can poll the descriptor for hotplug or state +change events. + +Applications must ignore operations (the "op" field) they do not handle, +this allows the API to be extended in the future. + +Additionally, each rfkill device is registered in sysfs and there has the +following attributes: name: Name assigned by driver to this key (interface or driver name). - type: Name of the key type ("wlan", "bluetooth", etc). + type: Driver type string ("wlan", "bluetooth", etc). state: Current state of the transmitter 0: RFKILL_STATE_SOFT_BLOCKED transmitter is turned off by software @@ -117,7 +119,12 @@ The following sysfs entries exist for every rfkill device: 2: RFKILL_STATE_HARD_BLOCKED transmitter is forced off by something outside of the driver's control. - claim: 0: Kernel handles events (currently always reads that value) + This file is deprecated because it can only properly show + three of the four possible states, soft-and-hard-blocked is + missing. + claim: 0: Kernel handles events + This file is deprecated because there no longer is a way to + claim just control over a single rfkill instance. rfkill devices also issue uevents (with an action of "change"), with the following environment variables set: @@ -128,9 +135,3 @@ RFKILL_TYPE The contents of these variables corresponds to the "name", "state" and "type" sysfs files explained above. - -An alternative userspace interface exists as a misc device /dev/rfkill, -which allows userspace to obtain and set the state of rfkill devices and -sets of devices. It also notifies userspace about device addition and -removal. The API is a simple read/write API that is defined in -linux/rfkill.h. diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index 34d54e7281f..de4aad076eb 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -1300,7 +1300,7 @@ isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) netif_stop_queue(ndev); } } - return 1; + return NETDEV_TX_BUSY; } /* diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 7e3738112c4..38f1c3375d7 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -3552,14 +3552,14 @@ bnx2_set_rx_mode(struct net_device *dev) sort_mode |= BNX2_RPM_SORT_USER0_MC_HSH_EN; } - if (dev->uc_count > BNX2_MAX_UNICAST_ADDRESSES) { + if (dev->uc.count > BNX2_MAX_UNICAST_ADDRESSES) { rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS; sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN | BNX2_RPM_SORT_USER0_PROM_VLAN; } else if (!(dev->flags & IFF_PROMISC)) { /* Add all entries into to the match filter list */ i = 0; - list_for_each_entry(ha, &dev->uc_list, list) { + list_for_each_entry(ha, &dev->uc.list, list) { bnx2_set_mac_addr(bp, ha->addr, i + BNX2_START_UNICAST_ADDRESS_INDEX); sort_mode |= (1 << diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c index 0e9b9f9632c..2df8fb0af70 100644 --- a/drivers/net/davinci_emac.c +++ b/drivers/net/davinci_emac.c @@ -2767,7 +2767,6 @@ static int __devexit davinci_emac_remove(struct platform_device *pdev) dev_notice(&ndev->dev, "DaVinci EMAC: davinci_emac_remove()\n"); - clk_disable(emac_clk); platform_set_drvdata(pdev, NULL); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); mdiobus_unregister(priv->mii_bus); diff --git a/drivers/net/e100.c b/drivers/net/e100.c index f7929e89eb0..efa680f4b8d 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -2895,12 +2895,13 @@ static void __e100_shutdown(struct pci_dev *pdev, bool *enable_wake) static int __e100_power_off(struct pci_dev *pdev, bool wake) { - if (wake) { + if (wake) return pci_prepare_to_sleep(pdev); - } else { - pci_wake_from_d3(pdev, false); - return pci_set_power_state(pdev, PCI_D3hot); - } + + pci_wake_from_d3(pdev, false); + pci_set_power_state(pdev, PCI_D3hot); + + return 0; } #ifdef CONFIG_PM diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 8d36743c814..5e3356f8eb5 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -2370,7 +2370,7 @@ static void e1000_set_rx_mode(struct net_device *netdev) rctl |= E1000_RCTL_VFE; } - if (netdev->uc_count > rar_entries - 1) { + if (netdev->uc.count > rar_entries - 1) { rctl |= E1000_RCTL_UPE; } else if (!(netdev->flags & IFF_PROMISC)) { rctl &= ~E1000_RCTL_UPE; @@ -2394,7 +2394,7 @@ static void e1000_set_rx_mode(struct net_device *netdev) */ i = 1; if (use_uc) - list_for_each_entry(ha, &netdev->uc_list, list) { + list_for_each_entry(ha, &netdev->uc.list, list) { if (i == rar_entries) break; e1000_rar_set(hw, ha->addr, i++); diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index b60a3041b64..1094d292630 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -719,7 +719,8 @@ static const struct register_test nv_registers_test[] = { struct nv_skb_map { struct sk_buff *skb; dma_addr_t dma; - unsigned int dma_len; + unsigned int dma_len:31; + unsigned int dma_single:1; struct ring_desc_ex *first_tx_desc; struct nv_skb_map *next_tx_ctx; }; @@ -1912,6 +1913,7 @@ static void nv_init_tx(struct net_device *dev) np->tx_skb[i].skb = NULL; np->tx_skb[i].dma = 0; np->tx_skb[i].dma_len = 0; + np->tx_skb[i].dma_single = 0; np->tx_skb[i].first_tx_desc = NULL; np->tx_skb[i].next_tx_ctx = NULL; } @@ -1930,23 +1932,30 @@ static int nv_init_ring(struct net_device *dev) return nv_alloc_rx_optimized(dev); } -static int nv_release_txskb(struct net_device *dev, struct nv_skb_map* tx_skb) +static void nv_unmap_txskb(struct fe_priv *np, struct nv_skb_map *tx_skb) { - struct fe_priv *np = netdev_priv(dev); - if (tx_skb->dma) { - pci_unmap_page(np->pci_dev, tx_skb->dma, - tx_skb->dma_len, - PCI_DMA_TODEVICE); + if (tx_skb->dma_single) + pci_unmap_single(np->pci_dev, tx_skb->dma, + tx_skb->dma_len, + PCI_DMA_TODEVICE); + else + pci_unmap_page(np->pci_dev, tx_skb->dma, + tx_skb->dma_len, + PCI_DMA_TODEVICE); tx_skb->dma = 0; } +} + +static int nv_release_txskb(struct fe_priv *np, struct nv_skb_map *tx_skb) +{ + nv_unmap_txskb(np, tx_skb); if (tx_skb->skb) { dev_kfree_skb_any(tx_skb->skb); tx_skb->skb = NULL; return 1; - } else { - return 0; } + return 0; } static void nv_drain_tx(struct net_device *dev) @@ -1964,10 +1973,11 @@ static void nv_drain_tx(struct net_device *dev) np->tx_ring.ex[i].bufhigh = 0; np->tx_ring.ex[i].buflow = 0; } - if (nv_release_txskb(dev, &np->tx_skb[i])) + if (nv_release_txskb(np, &np->tx_skb[i])) dev->stats.tx_dropped++; np->tx_skb[i].dma = 0; np->tx_skb[i].dma_len = 0; + np->tx_skb[i].dma_single = 0; np->tx_skb[i].first_tx_desc = NULL; np->tx_skb[i].next_tx_ctx = NULL; } @@ -2171,6 +2181,7 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) np->put_tx_ctx->dma = pci_map_single(np->pci_dev, skb->data + offset, bcnt, PCI_DMA_TODEVICE); np->put_tx_ctx->dma_len = bcnt; + np->put_tx_ctx->dma_single = 1; put_tx->buf = cpu_to_le32(np->put_tx_ctx->dma); put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags); |